Merge remote-tracking branch 'origin/glms/feature/1.4.2' into glms/feature/1.4.2
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
using YLErp.Models;
|
||||
|
||||
namespace YLErp
|
||||
@@ -135,6 +135,9 @@ namespace YLErp
|
||||
public const string Shibor = "Shibor";
|
||||
public const string FixingRepoRate = "FixingRepoRate";
|
||||
public const string OtherRate = "OtherRate";
|
||||
public const string BondYield = "BondYield"; //债券收益率
|
||||
public const string BondIndex = "BondIndex"; // 债券指数
|
||||
|
||||
//public const string OtherUnderlying = "OtherUnderlying";
|
||||
|
||||
|
||||
@@ -169,6 +172,8 @@ namespace YLErp
|
||||
//case OtherUnderlying: return "其他标的";
|
||||
case CreditBonds: return "信用债";
|
||||
case OtherBonds: return "其它债券";
|
||||
case BondYield: return "债券收益率";
|
||||
case BondIndex: return "债券指数";
|
||||
default: return instType;
|
||||
}
|
||||
}
|
||||
@@ -204,6 +209,8 @@ namespace YLErp
|
||||
//case "其他标的": return OtherUnderlying;
|
||||
case "信用债": return CreditBonds;
|
||||
case "其它债券": return OtherBonds;
|
||||
case "债券收益率": return BondYield;
|
||||
case "债券指数": return BondIndex;
|
||||
default: throw new ServiceException("资产类型不存在");
|
||||
}
|
||||
}
|
||||
@@ -264,6 +271,8 @@ namespace YLErp
|
||||
new SelectItem { Text = "汇率" ,Value = ExRate },
|
||||
new SelectItem { Text = "Shibor" ,Value = Shibor},
|
||||
new SelectItem { Text = "银行间回购定盘" ,Value = FixingRepoRate},
|
||||
new SelectItem { Text = "债券收益率" ,Value = BondYield},
|
||||
new SelectItem { Text = "债券指数" ,Value = BondIndex},
|
||||
//new SelectItem { Text = "其他利率" ,Value = OtherRate},
|
||||
//new SelectItem { Text = "其他标的" ,Value = OtherUnderlying}
|
||||
};
|
||||
@@ -271,7 +280,7 @@ namespace YLErp
|
||||
|
||||
public static IEnumerable<string> FutureTypes()
|
||||
{
|
||||
return new[] { CommodityFutures, StockIF, GoldFutures, TBFutures, OtherFutures, AbroadFutures };
|
||||
return new[] { CommodityFutures, StockIF, GoldFutures, TBFutures, OtherFutures, AbroadFutures, BondYield, BondIndex };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -371,8 +380,12 @@ namespace YLErp
|
||||
/// 类型转换为计算所用类型
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static string ConvertCalcType(string instType)
|
||||
public static string ConvertCalcType(string instType,bool pringScene = false)
|
||||
{
|
||||
if (pringScene && PS.Config.Company == Configuration.CompanyEnum.国联)
|
||||
{
|
||||
return Bonds;
|
||||
}
|
||||
switch (instType)
|
||||
{
|
||||
case Stock:
|
||||
@@ -390,6 +403,8 @@ namespace YLErp
|
||||
case TBFutures:
|
||||
case OtherFutures:
|
||||
case AbroadFutures:
|
||||
case BondYield:
|
||||
case BondIndex:
|
||||
return CommodityFutures;
|
||||
case CommoditySpot:
|
||||
case GoldSpot:
|
||||
@@ -414,7 +429,7 @@ namespace YLErp
|
||||
public static string[] GetFutureTypes()
|
||||
{
|
||||
return new[] { CommodityFutures, StockIF,
|
||||
GoldFutures, TBFutures, AbroadFutures, OtherFutures };
|
||||
GoldFutures, TBFutures, AbroadFutures, OtherFutures,BondYield,BondIndex };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -458,7 +473,7 @@ namespace YLErp
|
||||
Bonds,
|
||||
TBonds,
|
||||
CreditBonds,
|
||||
OtherBonds
|
||||
OtherBonds,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
|
||||
<PackageReference Include="NPOI" Version="2.5.6" />
|
||||
<PackageReference Include="RestSharp" Version="108.0.3" />
|
||||
<PackageReference Include="Qdp.Pricing.Base" Version="1.0.1" />
|
||||
<PackageReference Include="Qdp.Pricing.Base" Version="1.1.5-glms" />
|
||||
<PackageReference Include="TinyPinyin.Net" Version="1.0.2" />
|
||||
<PackageReference Include="YieldChain.Core" Version="1.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Qdp.ComputeService.Data.CommonModels.ValuationParams.Equity;
|
||||
using Qdp.ComputeService.Data.CommonModels.ValuationParams.Equity;
|
||||
using Qdp.ComputeService.Data.CommonModels.ValuationParams.FixedIncome;
|
||||
using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos;
|
||||
using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos.Options;
|
||||
@@ -59,7 +59,7 @@ namespace YLErp.BLL.Calculation.V2
|
||||
{
|
||||
underlying = underlying.Clone();
|
||||
|
||||
underlying.UnderlyingInstrumentType = ConsGlobal.InstrumentType.ConvertCalcType(underlying.UnderlyingInstrumentType);
|
||||
underlying.UnderlyingInstrumentType = ConsGlobal.InstrumentType.ConvertCalcType(underlying.UnderlyingInstrumentType,true);
|
||||
|
||||
switch (trade.TradeType)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using BaseOUDAL;
|
||||
using BaseOUDAL;
|
||||
using YLErp.Commons;
|
||||
using YLErp.Helpers;
|
||||
using YLErp.Modules;
|
||||
@@ -211,6 +211,27 @@ namespace YLErp.Model
|
||||
public double DividendRate { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Delta_R
|
||||
/// </summary>
|
||||
public double? Delta_r { get; set; }
|
||||
|
||||
public double? Delta_r_1bp { get; set; }
|
||||
|
||||
|
||||
public double? Dv01 { get; set; }
|
||||
|
||||
public double? Gamma_r { get; set; }
|
||||
|
||||
public double? Gamma_r_1bp { get; set; }
|
||||
|
||||
public double? Vega_r { get; set; }
|
||||
|
||||
public double? Vega_r_1bp { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 维持预付金
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Qdp.Foundation.Implementations;
|
||||
using Qdp.Foundation.Implementations;
|
||||
using Qdp.Pricing.Base.Enums;
|
||||
using Qdp.Pricing.Base.Implementations;
|
||||
using YLErp.Enums;
|
||||
@@ -105,7 +105,7 @@ namespace YLErp.Modules.CalculationModule
|
||||
public string underlyingInstrumentType
|
||||
{
|
||||
get => _underlyingInstrumentType;
|
||||
set => _underlyingInstrumentType = ConsGlobal.InstrumentType.ConvertCalcType(value);
|
||||
set => _underlyingInstrumentType = ConsGlobal.InstrumentType.ConvertCalcType(value,true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Qdp.Foundation.Implementations;
|
||||
using Qdp.Foundation.Implementations;
|
||||
using Qdp.Pricing.Base.Implementations;
|
||||
using Qdp.Pricing.Base.Interfaces;
|
||||
using Qdp.Pricing.Base.Utilities;
|
||||
@@ -570,7 +570,7 @@ namespace YLErp.Modules.CalculationModule
|
||||
{
|
||||
underlying = underlying.Clone();
|
||||
|
||||
underlying.UnderlyingInstrumentType = ConsGlobal.InstrumentType.ConvertCalcType(underlying.UnderlyingInstrumentType);
|
||||
underlying.UnderlyingInstrumentType = ConsGlobal.InstrumentType.ConvertCalcType(underlying.UnderlyingInstrumentType,true);
|
||||
|
||||
switch (trade.TradeType)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using YLErp.Abstract.DataProviders;
|
||||
using YLErp.Abstract.DataProviders;
|
||||
using YLErp.Helpers;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.TradeModule.DealModule;
|
||||
@@ -118,13 +118,13 @@ namespace YLErp.Modules.DataProviderModule
|
||||
ValueDate = ValueDate,
|
||||
UnderlyingId = um.id,
|
||||
UnderlyingCode = um.UnderlyingCode,
|
||||
ClosePrice = 0,
|
||||
SettlePrice = 0,
|
||||
ClosePrice = (double)(eodprice.net_price ?? 0) / 100,
|
||||
SettlePrice = (double)(eodprice.dirty_price_close ?? 0) / 100,
|
||||
HighPrice = 0,
|
||||
LowPrice = 0,
|
||||
UnderlyingStatus = "正常运行",
|
||||
UnderlyingInstrumentType = "Bonds",
|
||||
ReferencePrice = 0,
|
||||
ReferencePrice = (double)(eodprice.yield ?? 0),
|
||||
DeciSettlePrice = eodprice.dirty_price_close,
|
||||
DeciClosePrice = eodprice.net_price,
|
||||
DeciReferencePrice = eodprice.yield,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using BaseOUDAL;
|
||||
using BaseOUDAL;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
@@ -339,7 +339,9 @@ namespace YLErp.Modules.EodModule
|
||||
|
||||
var tcActions = new[] { ClientCashInCashOut.系统操作_平仓费,
|
||||
ClientCashInCashOut.系统操作_行权费,ClientCashInCashOut.系统操作_票息,ClientCashInCashOut.系统操作_互换,ClientCashInCashOut.人工操作_其他};
|
||||
|
||||
var underlyingCodes = searchResult.rows.Select(O => O.UnderlyingCode).Distinct().ToList();
|
||||
var greeksHandleService = new GLMSGreeksHandleService();
|
||||
greeksHandleService.InitData(req.ValueDate, underlyingCodes);
|
||||
foreach (var r in searchResult.rows)
|
||||
{
|
||||
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(r.UnderlyingCode);
|
||||
@@ -470,6 +472,7 @@ namespace YLErp.Modules.EodModule
|
||||
r.DeltaLots = (r.Delta ?? 0) / um.ContractSize;
|
||||
}
|
||||
r.Rho *= 100;
|
||||
greeksHandleService.Handle(r);
|
||||
if (r.trade == null)
|
||||
{
|
||||
r.TradeSinglePrice = r.etcTradePrice / r.TradeAmount;
|
||||
@@ -1118,6 +1121,9 @@ namespace YLErp.Modules.EodModule
|
||||
.AsEnumerable()
|
||||
.GroupBy(O => O.ParentTradeId)
|
||||
.ToDictionary(K => K.Key, V => V.Select(O => new xodTradeBase() { TradeJson = O.TradeJson }));
|
||||
var underlyingCodes = searchResult.rows.Select(O => O.UnderlyingCode).Distinct().ToList();
|
||||
var greeksHandleService = new GLMSGreeksHandleService();
|
||||
greeksHandleService.InitData(req.ValueDate, underlyingCodes);
|
||||
|
||||
foreach (var r in searchResult.rows)
|
||||
{
|
||||
@@ -1200,6 +1206,7 @@ namespace YLErp.Modules.EodModule
|
||||
}
|
||||
|
||||
r.Rho *= 100;
|
||||
greeksHandleService.Handle(r);
|
||||
r.CountRatio = um.CountRatio;
|
||||
r.TradeOriginalAmount = r.OriginalNotional / um.CountRatio;
|
||||
r.etcTradePrice = ConsTrade.TradeTypesForHedge.Contains(r.TradeType)
|
||||
@@ -1706,10 +1713,10 @@ namespace YLErp.Modules.EodModule
|
||||
var results = GetEodPositionRisksDataHandle(req);
|
||||
var list2 = results.Select(n => new ExpandoDictionary<string, string>(n)).ToArray();
|
||||
|
||||
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/日终持仓风险.xlsx");
|
||||
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/日终持仓风险_国联.xlsx");
|
||||
if (PS.Config.ErpElement.NeedShowSpv)
|
||||
{
|
||||
templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/日终持仓风险-Spv.xlsx");
|
||||
templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/日终持仓风险-Spv_国联.xlsx");
|
||||
}
|
||||
|
||||
return ExcelGenerator.UseTemplateGenerator(templateFile).AddVariable(new { list = list2 }).GenerateBytes();
|
||||
@@ -2016,6 +2023,17 @@ namespace YLErp.Modules.EodModule
|
||||
dic.Add("Spv3", item.PnLDelta.OtcFormat(OtcFormatFlag.greek));
|
||||
}
|
||||
|
||||
if (PS.Config.Company == Configuration.CompanyEnum.国联)
|
||||
{
|
||||
dic.Add("Delta_r", OtcFormatExtensions.OtcFormat(item.Delta_r, OtcFormatFlag.greek));
|
||||
dic.Add("Delta_r_1bp", OtcFormatExtensions.OtcFormat(item.Delta_r_1bp, OtcFormatFlag.greek));
|
||||
dic.Add("Dv01", OtcFormatExtensions.OtcFormat(item.Dv01, OtcFormatFlag.greek));
|
||||
dic.Add("Gamma_r", OtcFormatExtensions.OtcFormat(item.Gamma_r, OtcFormatFlag.greek));
|
||||
dic.Add("Gamma_r_1bp", OtcFormatExtensions.OtcFormat(item.Gamma_r_1bp, OtcFormatFlag.greek));
|
||||
dic.Add("Vega_r", OtcFormatExtensions.OtcFormat(item.Vega_r, OtcFormatFlag.greek));
|
||||
dic.Add("Vega_r_1bp", OtcFormatExtensions.OtcFormat(item.Vega_r_1bp, OtcFormatFlag.greek));
|
||||
}
|
||||
|
||||
|
||||
dic.Add("备注", item.Comments);
|
||||
|
||||
@@ -2115,6 +2133,17 @@ namespace YLErp.Modules.EodModule
|
||||
dic.Add("Spv2", "");
|
||||
dic.Add("Spv3", "");
|
||||
}
|
||||
|
||||
if (PS.Config.Company == Configuration.CompanyEnum.国联)
|
||||
{
|
||||
dic.Add("Delta_r", "");
|
||||
dic.Add("Delta_r_1bp", "");
|
||||
dic.Add("Dv01", "");
|
||||
dic.Add("Gamma_r", "");
|
||||
dic.Add("Gamma_r_1bp", "");
|
||||
dic.Add("Vega_r", "");
|
||||
dic.Add("Vega_r_1bp", "");
|
||||
}
|
||||
results.Add(dic);
|
||||
}
|
||||
return results;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using YLErp.Model;
|
||||
|
||||
namespace YLErp.Modules.EodModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 国联民生 希腊字母计算
|
||||
/// </summary>
|
||||
public class GLMSGreeksHandleService
|
||||
{
|
||||
|
||||
public void InitData(DateTime valueDate,List<string> underlyingCodes)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void Handle(EodPositionRisksDTO dto)
|
||||
{
|
||||
//对Delta_r Delta_r_1bp Dv01 Gamma_r Gamma_r_1bp Vega_r Vega_r_1bp
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace YLErp.Modules.EodModule.SettlementModule
|
||||
if (request.IsSettleOtcTrades)
|
||||
{
|
||||
var tradePredicate = _context.PredicateBuilder.GetOtcTradePredicate()
|
||||
.And(t => t.TradeType != "自定义交易" && t.TradeType != "收益互换" && t.UnderlyingCode != null);
|
||||
.And(t => t.TradeType != "自定义交易" && t.UnderlyingCode != null);
|
||||
|
||||
//新增客户筛选 tw
|
||||
if (clienIds != null)
|
||||
@@ -58,6 +58,11 @@ namespace YLErp.Modules.EodModule.SettlementModule
|
||||
|
||||
allQuery = DbContext.trade.Where(tradePredicate).Select(n => n.UnderlyingCode).Distinct();
|
||||
|
||||
if (PS.Config.ErpElement.ForwardTradePriceModel == Configuration.Enums.ForwardTradePriceModel.STANDARD)
|
||||
{
|
||||
allQuery = allQuery.Union(DbContext.trade.Where(tradePredicate).Where(x => x.BasisUnderlyingCode != null && x.BasisUnderlyingCode != "").Select(n => n.BasisUnderlyingCode).Distinct());
|
||||
}
|
||||
|
||||
var clientProductPredicate = _context.PredicateBuilder.GetClientProductPredicate();
|
||||
|
||||
//新增客户筛选 tw
|
||||
@@ -74,26 +79,28 @@ namespace YLErp.Modules.EodModule.SettlementModule
|
||||
}
|
||||
|
||||
//检查场内标的
|
||||
//if (request.IsSettleExchangeTrades)
|
||||
//{
|
||||
// var exTradePredicate = _context.PredicateBuilder.GetExchangeTradePredicate();
|
||||
if (request.IsSettleExchangeTrades)
|
||||
{
|
||||
var exTradePredicate = _context.PredicateBuilder.GetExchangeTradePredicate();
|
||||
|
||||
// var exTradeQuery = DbContext.ExchangeTrade.Where(exTradePredicate).Select(n => n.UnderlyingCode);
|
||||
var exTradeQuery = DbContext.ExchangeTrade.Where(exTradePredicate).Select(n => n.UnderlyingCode);
|
||||
|
||||
// allQuery = allQuery == null ? exTradeQuery.Distinct() : allQuery.Union(exTradeQuery.Distinct());
|
||||
allQuery = allQuery == null ? exTradeQuery.Distinct() : allQuery.Union(exTradeQuery.Distinct());
|
||||
|
||||
// var preSettleDate = _context.PreSettleDate;
|
||||
// //最后一个交易日持仓信息
|
||||
// var futureTypes = ConsGlobal.InstrumentType.GetFutureTypes();
|
||||
// var positionQuery = from t in DbContext.eod_trade_position
|
||||
// join um in DbContext.underlying_manager on t.UnderlyingCode equals um.UnderlyingCode
|
||||
// where t.ValueDate == preSettleDate && t.Amount != 0
|
||||
// && ConsTrade.TradeTypesForHedge.Contains(t.TradeType)
|
||||
// && (!futureTypes.Contains(um.UnderlyingInstrumentType) || um.MaturityDate >= settleDate)
|
||||
// select t.UnderlyingCode;
|
||||
var preSettleDate = _context.PreSettleDate;
|
||||
//最后一个交易日持仓信息
|
||||
var futureTypes = ConsGlobal.InstrumentType.GetFutureTypes();
|
||||
var positionQuery = from t in DbContext.eod_trade_position
|
||||
join um in DbContext.underlying_manager on t.UnderlyingCode equals um.UnderlyingCode
|
||||
where t.ValueDate == preSettleDate && t.Amount != 0
|
||||
&& ConsTrade.TradeTypesForHedge.Contains(t.TradeType)
|
||||
&& (!futureTypes.Contains(um.UnderlyingInstrumentType) || um.MaturityDate >= settleDate)
|
||||
select t.UnderlyingCode;
|
||||
|
||||
// allQuery = allQuery.Union(positionQuery.Distinct());
|
||||
//}
|
||||
allQuery = allQuery.Union(positionQuery.Distinct());
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (allQuery == null)
|
||||
{
|
||||
@@ -103,12 +110,10 @@ namespace YLErp.Modules.EodModule.SettlementModule
|
||||
//检查是否所有标的都在结算日有结算价格
|
||||
|
||||
var umCodeArr = allQuery.ToArray();
|
||||
var swapUmCodeArr = GetSwapUnderlyingCodes();
|
||||
var codeArr = umCodeArr.Union(swapUmCodeArr);
|
||||
var eodPriceProvider = _context.GetEodPriceProvider().Initialize(codeArr);
|
||||
// var preEodPriceProvidaer = _context.GetPreEodPriceProvider().Initialize(swapUmCodeArr);
|
||||
var umCodes = codeArr.Where(n => !string.IsNullOrEmpty(n) && !eodPriceProvider.HasValue(n)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
//var swapUmCodes= swapUmCodeArr.Where(n => !string.IsNullOrEmpty(n) && !preEodPriceProvidaer.HasValue(n)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var eodPriceProvider = _context.GetEodPriceProvider().Initialize(umCodeArr);
|
||||
var umCodes = umCodeArr.Where(n => !string.IsNullOrEmpty(n) && !eodPriceProvider.HasValue(n)).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
//排除掉节假日不需要结算的交易
|
||||
foreach (var t in _context.HolidayTrades)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using BaseOUDAL;
|
||||
using BaseOUDAL;
|
||||
using YLErp.BLL;
|
||||
using YLErp.Configuration;
|
||||
using YLErp.Configuration.Enums;
|
||||
@@ -993,10 +993,10 @@ namespace YLErp.Modules.TradeModule.OrderModule
|
||||
throw new ServiceException($"客户'{client.Name}'为非高风险客户,没有卖出权限");
|
||||
}
|
||||
|
||||
if (_underlying != null && _underlying.CalcTypeIsStock() && ((client.TradingInstType & TradingInstTypeEnum.Equity) != TradingInstTypeEnum.Equity))
|
||||
{
|
||||
throw new ServiceException($"客户'{client.Name}'的'交易资产'属性不包括'权益',不能进行权益类的期权交易");
|
||||
}
|
||||
//if (_underlying != null && _underlying.CalcTypeIsStock() && ((client.TradingInstType & TradingInstTypeEnum.Equity) != TradingInstTypeEnum.Equity))
|
||||
//{
|
||||
// throw new ServiceException($"客户'{client.Name}'的'交易资产'属性不包括'权益',不能进行权益类的期权交易");
|
||||
//}
|
||||
|
||||
if (PS.Config.ErpElement.SecuritiesEnvironment)
|
||||
{
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
<PackageReference Include="Snowflake.Core" Version="2.0.0" />
|
||||
<PackageReference Include="SocialExplorer.FastDBF" Version="1.0.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.10.0" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.0" />
|
||||
<PackageReference Include="Qdp.Pricing.Library.Options" Version="1.0.5" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
|
||||
<PackageReference Include="YLErp.Office" Version="1.1.2" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.0.5" />
|
||||
<PackageReference Include="Qdp.Pricing.Library.Options" Version="5.18.4-glms" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||
<PackageReference Include="YLErp.Office" Version="1.4.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -7055,6 +7055,10 @@ namespace YLErp.Web.Controllers
|
||||
|
||||
public JsonResult BatchDownloadEodPositionRisks(EodPositionRisksReq req)
|
||||
{
|
||||
req.BookIds = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.BookIds).ToList();
|
||||
req.UserAssets = CurUser.GetAssetUnitIds();
|
||||
req.UserClients = CurUser.GetClientIdsByCurUser(CurUser.交易管理_查看所有交易);
|
||||
if (CurUser.交易管理_查看所有交易) { req.UserClients.Clear(); }
|
||||
if (!new EodPositionRisksQueryService(CurUser).BatchDownloadEodPositionRisks(req))
|
||||
{
|
||||
return JsonError("线程正在被占用");
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
})
|
||||
function CaptchaClick(){
|
||||
var img = document.getElementById('captcha');
|
||||
if (!img) return; // NeedCaptcha=false 时验证码 img 不渲染,避免 null.setAttribute 报错
|
||||
var newSrc = '@captchaUrl' + '&t=' + new Date().getTime();
|
||||
img.setAttribute('src', newSrc);
|
||||
}
|
||||
|
||||
@@ -44,6 +44,15 @@
|
||||
.no-skin {
|
||||
position: static !important;
|
||||
}
|
||||
|
||||
.searchdiv .contract-code-search-group {
|
||||
width: 272px;
|
||||
}
|
||||
|
||||
.searchdiv .contract-code-search-group .search-label {
|
||||
width: 110px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
@section JS{
|
||||
@@ -57,7 +66,17 @@
|
||||
|
||||
<div class="searchdiv">
|
||||
@Html.ShortInput("TradeNumber", "交易编号")
|
||||
@Html.ShortInput("ContractCode", pageObj.isGuoLian ? "交易确认书编号" : "合约编号")
|
||||
@if (pageObj.isGuoLian)
|
||||
{
|
||||
<div class="search-group contract-code-search-group">
|
||||
<span class="search-label" for="ContractCode">交易确认书编号</span>
|
||||
<input class="search-input" id="ContractCode" name="ContractCode" type="text" value="@(ViewData["ContractCode"] ?? "")" autocomplete="off" />
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Html.ShortInput("ContractCode", "合约编号")
|
||||
}
|
||||
@Html.MyAceDropdownInput("ClientId", "客户名称", ClientDataModel.GetAllClient())
|
||||
@Html.MyAceDropdownInput("AssetId", "簿记账户", AssetunitController.GetClientassetunit())
|
||||
@Html.MyAceDropdownInput("GroupId", "簿记账户组", AssetUnitModel.GetAllAssetUnitGroupItem())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@{
|
||||
@{
|
||||
ViewBag.Title = "日终持仓风险";
|
||||
Layout = "~/Views/Shared/_MainLayout.cshtml";
|
||||
var settleConfig = PS.Config.GetSettlementConfig();
|
||||
@@ -19,7 +19,8 @@
|
||||
IsUseDisplayNotional = PS.Config.IsUseDisplayNotional,
|
||||
showGuohai = PS.Config.Is国海,
|
||||
isGuoyuan = PS.Config.Company==CompanyEnum.国元固收,
|
||||
isGuoJun = PS.Config.IsGuoJun
|
||||
isGuoJun = PS.Config.IsGuoJun,
|
||||
isGLMS = PS.Config.Company == CompanyEnum.国联
|
||||
};
|
||||
}
|
||||
<style>
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
<PackageReference Include="RazorEngineCore" Version="2022.8.1" />
|
||||
<PackageReference Include="RazorLight-rpm" Version="3.0.0" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="2.88.6" />
|
||||
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="6.0.1" />
|
||||
<PackageReference Include="DocumentFormat.OpenXml" Version="2.7.2" />
|
||||
<PackageReference Include="System.IO.Packaging" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
@@ -105,6 +104,9 @@
|
||||
<None Update="App_Docs\导出模板\客户盈亏状况模板.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="App_Docs\导出模板\日终持仓风险_国联.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="App_Docs\导出模板\日终持仓风险.xlsx">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
@@ -242,10 +244,8 @@
|
||||
<_RebuildScript>$(MSBuildProjectDirectory)\rebuild-bundles.ps1</_RebuildScript>
|
||||
<_RebuildScriptSh>$(MSBuildProjectDirectory)/rebuild-bundles.sh</_RebuildScriptSh>
|
||||
</PropertyGroup>
|
||||
<Exec Condition="'$(OS)' == 'Windows_NT'"
|
||||
Command="powershell -ExecutionPolicy Bypass -File "$(_RebuildScript)"" />
|
||||
<Exec Condition="'$(OS)' != 'Windows_NT'"
|
||||
Command="bash "$(_RebuildScriptSh)"" />
|
||||
<Exec Condition="'$(OS)' == 'Windows_NT'" Command="powershell -ExecutionPolicy Bypass -File "$(_RebuildScript)"" />
|
||||
<Exec Condition="'$(OS)' != 'Windows_NT'" Command="bash "$(_RebuildScriptSh)"" />
|
||||
</Target>
|
||||
|
||||
<!-- 手动校验 target:dotnet build -t:VerifyBundles
|
||||
@@ -257,10 +257,8 @@
|
||||
<_RebuildScript>$(MSBuildProjectDirectory)\rebuild-bundles.ps1</_RebuildScript>
|
||||
<_RebuildScriptSh>$(MSBuildProjectDirectory)/rebuild-bundles.sh</_RebuildScriptSh>
|
||||
</PropertyGroup>
|
||||
<Exec Condition="'$(OS)' == 'Windows_NT'"
|
||||
Command="powershell -ExecutionPolicy Bypass -File "$(_RebuildScript)" -Verify" />
|
||||
<Exec Condition="'$(OS)' != 'Windows_NT'"
|
||||
Command="bash "$(_RebuildScriptSh)" --verify" />
|
||||
<Exec Condition="'$(OS)' == 'Windows_NT'" Command="powershell -ExecutionPolicy Bypass -File "$(_RebuildScript)" -Verify" />
|
||||
<Exec Condition="'$(OS)' != 'Windows_NT'" Command="bash "$(_RebuildScriptSh)" --verify" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyFilesAfterPublish" AfterTargets="Publish">
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* swapPriceInput.component.test.js — vue-swap-price-input 事件派发回归守卫
|
||||
* ============================================================================
|
||||
* 目的:锁定债券三字段输入组件「粘贴 / 重输原值 不派发 input/enter」的 bug。
|
||||
* 症状:粘贴或重输原值后,点空白(标REV/清其他标识)与回车(触发计算)均无反应。
|
||||
* 根因:组件把 input/enter 全部锁在原生 change 事件里,而 change 仅在「值相对聚焦时
|
||||
* 变动」才触发;onPaste 甚至完全不派发任何事件。
|
||||
*
|
||||
* 做法:直接实例化组件 options 对象(createVueInputComponent),用 mock this + $emit 间谍
|
||||
* 驱动 onPaste/onKeydown/onChange,断言事件派发。不依赖 Vue 运行时挂载、不改动源文件。
|
||||
*
|
||||
* 运行:cd YLErpWeb/fe-tests && npx jest swapPriceInput.component
|
||||
* 设 SWAP_PRICE_HELPER 指向其它版本文件可做对照(如改之前的旧代码应使用例变红)。
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function loadComponent() {
|
||||
const rel = process.env.SWAP_PRICE_HELPER
|
||||
|| '../wwwroot/Scripts/app/swaptrade/swapPricePrecisionHelper.js';
|
||||
const file = path.resolve(__dirname, rel);
|
||||
const code = fs.readFileSync(file, 'utf8');
|
||||
// swapPricePrecisionHelper.js: var swapPricePrecision = (function(global){...})(window);
|
||||
// 在受控作用域求值并取出 createVueInputComponent(IIFE 不挂 window,故用 new Function 取返回值)。
|
||||
const factory = new Function('window', 'global', 'console', code + '\n;return swapPricePrecision;');
|
||||
const sandbox = {};
|
||||
const swapPricePrecision = factory(sandbox, sandbox, console);
|
||||
return swapPricePrecision.createVueInputComponent();
|
||||
}
|
||||
|
||||
function makeCtx(component, opts) {
|
||||
opts = opts || {};
|
||||
const emitted = [];
|
||||
const ctx = {
|
||||
text: opts.text != null ? String(opts.text) : '',
|
||||
enterPressed: false,
|
||||
formatSnapshot: '{}',
|
||||
format: opts.format || { integerDigits: 2, precision: 4, percent: true },
|
||||
$emit: function (name, payload) { emitted.push({ name: name, payload: payload }); },
|
||||
};
|
||||
Object.keys(component.methods).forEach(function (m) {
|
||||
ctx[m] = component.methods[m].bind(ctx);
|
||||
});
|
||||
return { ctx: ctx, emitted: emitted };
|
||||
}
|
||||
|
||||
describe('vue-swap-price-input 事件派发(粘贴 / 重输原值场景)', () => {
|
||||
const component = loadComponent();
|
||||
|
||||
test('粘贴原值应派发 input(点空白标REV / 清其他标识)', () => {
|
||||
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { integerDigits: 2, precision: 4, percent: true } });
|
||||
const evt = { preventDefault() {}, clipboardData: { getData: () => '3.5' }, target: { value: '' } };
|
||||
ctx.onPaste(evt);
|
||||
const inputs = emitted.filter(e => e.name === 'input');
|
||||
expect(inputs.length).toBe(1);
|
||||
expect(inputs[0].payload).toBe('0.035'); // percent:true → ÷100
|
||||
});
|
||||
|
||||
test('回车(原值未变)应派发 enter(触发自动计算)', () => {
|
||||
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { integerDigits: 2, precision: 4, percent: true } });
|
||||
const evt = { which: 13, keyCode: 13, key: 'Enter', target: { blur() {}, value: '3.5' } };
|
||||
ctx.onKeydown(evt);
|
||||
const enters = emitted.filter(e => e.name === 'enter');
|
||||
expect(enters.length).toBe(1);
|
||||
expect(enters[0].payload).toBe('0.035');
|
||||
});
|
||||
|
||||
test('回车(值已改)应派发 input+enter 各一次,且不重复派发 enter', () => {
|
||||
const { ctx, emitted } = makeCtx(component, { text: '3.6', format: { percent: true } });
|
||||
const evt = { which: 13, keyCode: 13, key: 'Enter', target: { blur() {}, value: '3.6' } };
|
||||
ctx.onKeydown(evt);
|
||||
expect(emitted.filter(e => e.name === 'input').length).toBe(1);
|
||||
expect(emitted.filter(e => e.name === 'enter').length).toBe(1);
|
||||
});
|
||||
|
||||
test('非 Enter 按键不应派发 enter / input', () => {
|
||||
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { percent: true } });
|
||||
const evt = { which: 65, keyCode: 65, key: 'a', target: { blur() {} } };
|
||||
ctx.onKeydown(evt);
|
||||
expect(emitted.filter(e => e.name === 'enter').length).toBe(0);
|
||||
expect(emitted.filter(e => e.name === 'input').length).toBe(0);
|
||||
});
|
||||
|
||||
test('失焦(onChange)即使值未变也应派发 input(点空白标REV),且不再派发 enter', () => {
|
||||
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { percent: true } });
|
||||
const evt = { target: { value: '3.5' } };
|
||||
ctx.onChange(evt);
|
||||
expect(emitted.filter(e => e.name === 'input').length).toBe(1);
|
||||
expect(emitted.filter(e => e.name === 'enter').length).toBe(0);
|
||||
});
|
||||
|
||||
test('粘贴但格式为 percent:false 也应派发 input(原值透传)', () => {
|
||||
const { ctx, emitted } = makeCtx(component, { text: '3.5', format: { integerDigits: 2, precision: 4, percent: false } });
|
||||
const evt = { preventDefault() {}, clipboardData: { getData: () => '3.5' }, target: { value: '' } };
|
||||
ctx.onPaste(evt);
|
||||
expect(emitted.filter(e => e.name === 'input').length).toBe(1);
|
||||
expect(emitted.filter(e => e.name === 'input')[0].payload).toBe('3.5');
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
function getColModelGrid() {
|
||||
function getColModelGrid() {
|
||||
var i = 0;
|
||||
var colModelGrid = [
|
||||
{ name: 'id', hidden: true, optionHide: true },
|
||||
@@ -494,6 +494,75 @@
|
||||
colModelGrid = colModelGrid.concat(spvCols);
|
||||
}
|
||||
|
||||
|
||||
if (page.isGLMS) {
|
||||
colModelGrid.push({
|
||||
name: 'Delta_r',
|
||||
label: 'Delta_r',
|
||||
index: 'Delta_r',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
sortIndex: i++,
|
||||
formatter: greeksFormat,
|
||||
sortable: false
|
||||
}, {
|
||||
name: 'Delta_r_1bp',
|
||||
label: 'Delta_r(1bp)',
|
||||
index: 'Delta_r_1bp',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
sortIndex: i++,
|
||||
formatter: greeksFormat,
|
||||
sortable: false
|
||||
}, {
|
||||
name: 'Dv01',
|
||||
label: 'Dv01',
|
||||
index: 'Dv01',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
sortIndex: i++,
|
||||
formatter: greeksFormat,
|
||||
sortable: false
|
||||
}, {
|
||||
name: 'Gamma_r',
|
||||
label: 'Gamma_r',
|
||||
index: 'Gamma_r',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
sortIndex: i++,
|
||||
formatter: greeksFormat,
|
||||
sortable: false
|
||||
}, {
|
||||
name: 'Gamma_r_1bp',
|
||||
label: 'Gamma_r(1bp)',
|
||||
index: 'Gamma_r_1bp',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
sortIndex: i++,
|
||||
formatter: greeksFormat,
|
||||
sortable: false
|
||||
}, {
|
||||
name: 'Vega_r',
|
||||
label: 'Vega_r',
|
||||
index: 'Vega_r',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
sortIndex: i++,
|
||||
formatter: greeksFormat,
|
||||
sortable: false
|
||||
}, {
|
||||
name: 'Vega_r_1bp',
|
||||
label: 'Vega_r(1bp)',
|
||||
index: 'Vega_r_1bp',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
sortIndex: i++,
|
||||
formatter: greeksFormat,
|
||||
sortable: false
|
||||
},);
|
||||
|
||||
}
|
||||
|
||||
return tradeHelper.getAmountToNotional(colModelGrid);
|
||||
}
|
||||
|
||||
@@ -594,6 +663,13 @@ function TradeAmountFormat(cellValue, options, rowObject) {
|
||||
return otcformat.trading.notional(cellValue);
|
||||
}
|
||||
|
||||
function greeksFormat(cellValue, options, rowObject) {
|
||||
if (cellValue) {
|
||||
return otcformat.trading.greek(cellValue);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function SpotPriceFormat(cellValue, options, rowObject) {
|
||||
if (rowObject.TradeType !== "场内期权" && rowObject.TradeType !== "商品期货" && rowObject.TradeType !== "股票" && rowObject.TradeType !== "商品现货") {
|
||||
return otcformat.trading.umprice(cellValue)
|
||||
|
||||
@@ -208,22 +208,32 @@ var swapPricePrecision = (function (global) {
|
||||
event.preventDefault();
|
||||
this.updateValue(clipboard.getData('text'), true, false);
|
||||
event.target.value = this.text;
|
||||
// 粘贴即显式赋值意图:直接派发 input,使「单击空白处标REV/其余清空」「回车前已标记」等行为生效。
|
||||
// 原实现只把粘贴内容写回DOM、等失焦时的原生change才派发,而原值粘贴时change不触发→静默无反应。
|
||||
this.$emit('input', this.toModel(this.text));
|
||||
},
|
||||
onKeydown: function (event) {
|
||||
this.enterPressed = false;
|
||||
this.$emit('keydown', event);
|
||||
const keyCode = event.which || event.keyCode;
|
||||
if (event.key !== 'Enter' && keyCode !== 13 && keyCode !== 108) return;
|
||||
this.enterPressed = true;
|
||||
event.target.blur();
|
||||
// 回车=用户显式提交意图:无论值是否相对聚焦时变化,都直接派发 input(标REV) + enter(触发计算)。
|
||||
// 原实现把 enter 锁在原生 change 里,而 change 仅在值变化时触发,
|
||||
// 导致「重输/重贴原值 + 回车」静默不计算(QA 高优 Bug)。
|
||||
this.updateValue(this.text, true, false);
|
||||
const value = this.toModel(this.text);
|
||||
event.target.blur(); // 同步触发原生 change(值变化时再派发一次 input,幂等无害)
|
||||
this.$emit('input', value);
|
||||
this.$emit('enter', value);
|
||||
this.enterPressed = false;
|
||||
},
|
||||
onChange: function (event) {
|
||||
if (this.text.endsWith('.')) this.text = this.text.substring(0, this.text.length - 1);
|
||||
this.updateValue(this.text, true, false);
|
||||
const value = this.toModel(this.text);
|
||||
// 失焦(非回车)→ 仅派发 input 标 REV;enter(计算) 改由 onKeydown 直接派发,
|
||||
// 避免 change 不触发时丢失,也避免与 onKeydown 重复派发 enter 造成重复计算。
|
||||
this.$emit('input', value);
|
||||
if (this.enterPressed) this.$emit('enter', value);
|
||||
this.enterPressed = false;
|
||||
event.target.value = this.text;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -14667,6 +14667,7 @@ $.fn.selectpicker.Constructor.DEFAULTS = Object.assign($.fn.selectpicker.Constru
|
||||
};
|
||||
|
||||
}(window.FastVue));
|
||||
|
||||
//日期选择组件FastVue.DatePicker
|
||||
(function (global) {
|
||||
global.vueDatePicker = function () {
|
||||
@@ -15009,21 +15010,35 @@ $.fn.selectpicker.Constructor.DEFAULTS = Object.assign($.fn.selectpicker.Constru
|
||||
//依赖类库:lodash.js + jquery + jquery.validate + bootstrap.emodal.js
|
||||
|
||||
// 统一调试日志工具:仅在 otcdebug 开启时输出,默认静默(生产零噪音)。
|
||||
// 开启方式:URL 加 ?otcdebug=1,或控制台 localStorage.setItem('otcdebug','1')。
|
||||
// 业务脚本逐步改用 otcDebug.banner / otcDebug.log 替代裸 console.log,
|
||||
// 既能在排查时一键全开,又能避免版本标记散落硬编码(见 swapTradeEdit.js / fastVue.base.js 用法)。
|
||||
var __otcDiag = (window.ylotc && window.ylotc.__diag) || { debug: false };
|
||||
// 开启:URL 加 ?otcdebug=1(会自动写入 localStorage,同源 iframe/弹窗自动继承);
|
||||
// 或控制台 localStorage.setItem('otcdebug','1')。关闭:localStorage.removeItem('otcdebug')。
|
||||
// 业务脚本用 otcDebug.banner / otcDebug.log 替代裸 console.log(见 swapTradeEdit.js / fastVue.base.js)。
|
||||
//
|
||||
// 命名约定(避免 __私有对象 + otcDebug.API 大小写混搭):
|
||||
// __diag —— 版本元数据对象(仅 _MainLayout 灌入 ylotc.__diag 时存在,仅供 banner 展示,不参与开关判定)
|
||||
// __debug —— 调试开关布尔值(唯一真相来源:localStorage 优先 → URL 参数 → 兜底 __diag.debug)
|
||||
var __diag = (window.ylotc && window.ylotc.__diag) || {};
|
||||
var __debug = (function () {
|
||||
try {
|
||||
// 1) URL 参数优先(排查最直观);命中即写入 localStorage,供同源 iframe/弹窗继承
|
||||
if (/[?&]otcdebug=1/.test(location.search)) { localStorage.setItem('otcdebug', '1'); return true; }
|
||||
// 2) 已持久化的开关(父页面开过一次,_InfoLayout 弹窗自动生效)
|
||||
if (localStorage.getItem('otcdebug') === '1') return true;
|
||||
} catch (e) { /* localStorage 不可用时忽略,继续走兜底 */ }
|
||||
// 3) 兜底:layout 灌入的 ylotc.__diag.debug(仅 _MainLayout 有)
|
||||
return !!__diag.debug;
|
||||
})();
|
||||
window.otcDebug = {
|
||||
// 模块加载横幅:F12 一眼看到模块名+bundle版本+git sha,用于排查"是不是加载了旧代码/旧缓存"
|
||||
// 模块加载横幅:F12 一眼看到模块名+版本,用于排查"是不是加载了旧代码/旧缓存"
|
||||
banner: function (name, ver) {
|
||||
if (!__otcDiag.debug || !window.console) return;
|
||||
var git = (__otcDiag.git || '').slice(0, 7);
|
||||
console.log('%c[' + name + '] v' + ver + ' (bundle=' + __otcDiag.jsVersion + ', git=' + git + ', built=' + __otcDiag.built + ')',
|
||||
if (!__debug || !window.console) return;
|
||||
var git = (__diag.git || '').slice(0, 7);
|
||||
console.log('%c[' + name + '] v' + ver + ' (bundle=' + __diag.jsVersion + ', git=' + git + ', built=' + __diag.built + ')',
|
||||
'color:#06c;font-weight:bold');
|
||||
},
|
||||
// 普通调试日志:透传参数,仅 debug 开启时输出
|
||||
log: function () {
|
||||
if (!__otcDiag.debug || !window.console) return;
|
||||
if (!__debug || !window.console) return;
|
||||
console.log.apply(console, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -802,21 +802,35 @@ An}();typeof define=="function"&&typeof define.amd=="object"&&define.amd?($n._=r
|
||||
//依赖类库:lodash.js + jquery + jquery.validate + bootstrap.emodal.js
|
||||
|
||||
// 统一调试日志工具:仅在 otcdebug 开启时输出,默认静默(生产零噪音)。
|
||||
// 开启方式:URL 加 ?otcdebug=1,或控制台 localStorage.setItem('otcdebug','1')。
|
||||
// 业务脚本逐步改用 otcDebug.banner / otcDebug.log 替代裸 console.log,
|
||||
// 既能在排查时一键全开,又能避免版本标记散落硬编码(见 swapTradeEdit.js / fastVue.base.js 用法)。
|
||||
var __otcDiag = (window.ylotc && window.ylotc.__diag) || { debug: false };
|
||||
// 开启:URL 加 ?otcdebug=1(会自动写入 localStorage,同源 iframe/弹窗自动继承);
|
||||
// 或控制台 localStorage.setItem('otcdebug','1')。关闭:localStorage.removeItem('otcdebug')。
|
||||
// 业务脚本用 otcDebug.banner / otcDebug.log 替代裸 console.log(见 swapTradeEdit.js / fastVue.base.js)。
|
||||
//
|
||||
// 命名约定(避免 __私有对象 + otcDebug.API 大小写混搭):
|
||||
// __diag —— 版本元数据对象(仅 _MainLayout 灌入 ylotc.__diag 时存在,仅供 banner 展示,不参与开关判定)
|
||||
// __debug —— 调试开关布尔值(唯一真相来源:localStorage 优先 → URL 参数 → 兜底 __diag.debug)
|
||||
var __diag = (window.ylotc && window.ylotc.__diag) || {};
|
||||
var __debug = (function () {
|
||||
try {
|
||||
// 1) URL 参数优先(排查最直观);命中即写入 localStorage,供同源 iframe/弹窗继承
|
||||
if (/[?&]otcdebug=1/.test(location.search)) { localStorage.setItem('otcdebug', '1'); return true; }
|
||||
// 2) 已持久化的开关(父页面开过一次,_InfoLayout 弹窗自动生效)
|
||||
if (localStorage.getItem('otcdebug') === '1') return true;
|
||||
} catch (e) { /* localStorage 不可用时忽略,继续走兜底 */ }
|
||||
// 3) 兜底:layout 灌入的 ylotc.__diag.debug(仅 _MainLayout 有)
|
||||
return !!__diag.debug;
|
||||
})();
|
||||
window.otcDebug = {
|
||||
// 模块加载横幅:F12 一眼看到模块名+bundle版本+git sha,用于排查"是不是加载了旧代码/旧缓存"
|
||||
// 模块加载横幅:F12 一眼看到模块名+版本,用于排查"是不是加载了旧代码/旧缓存"
|
||||
banner: function (name, ver) {
|
||||
if (!__otcDiag.debug || !window.console) return;
|
||||
var git = (__otcDiag.git || '').slice(0, 7);
|
||||
console.log('%c[' + name + '] v' + ver + ' (bundle=' + __otcDiag.jsVersion + ', git=' + git + ', built=' + __otcDiag.built + ')',
|
||||
if (!__debug || !window.console) return;
|
||||
var git = (__diag.git || '').slice(0, 7);
|
||||
console.log('%c[' + name + '] v' + ver + ' (bundle=' + __diag.jsVersion + ', git=' + git + ', built=' + __diag.built + ')',
|
||||
'color:#06c;font-weight:bold');
|
||||
},
|
||||
// 普通调试日志:透传参数,仅 debug 开启时输出
|
||||
log: function () {
|
||||
if (!__otcDiag.debug || !window.console) return;
|
||||
if (!__debug || !window.console) return;
|
||||
console.log.apply(console, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user