diff --git a/YLErpDAL/AppManager.cs b/YLErpDAL/AppManager.cs index 0b244c2d..609c870a 100644 --- a/YLErpDAL/AppManager.cs +++ b/YLErpDAL/AppManager.cs @@ -171,6 +171,7 @@ namespace YLErp "yladmin" => _configuration.GetConnectionString("yladmin"), "ylclient" => _configuration.GetConnectionString("ylclient"), "bondoms" => _configuration.GetConnectionString("bondoms"), + "glms_bigdata" => _configuration.GetConnectionString("glms_bigdata"), "apex_oracle"=> _configuration.GetConnectionString("apex_oracle"), _ => string.Empty, }; diff --git a/YLErpDAL/Modules/UnderlyingModule/FundManagerLookupService.cs b/YLErpDAL/Modules/UnderlyingModule/FundManagerLookupService.cs new file mode 100644 index 00000000..b37d8f5e --- /dev/null +++ b/YLErpDAL/Modules/UnderlyingModule/FundManagerLookupService.cs @@ -0,0 +1,94 @@ +using Dapper; +using MySqlConnector; +using YieldChain.Helpers; +using YLErp.BLL; + +namespace YLErp.Modules.UnderlyingModule +{ + public enum FundManagerLookupStatus + { + NotFound, + Unique, + Multiple, + Unavailable + } + + public sealed class FundManagerLookupResult + { + public FundManagerLookupStatus Status { get; init; } + public string InvestAdvisorName { get; init; } + } + + /// + /// 查询上游基金档案中的基金管理人。上游不可用时返回降级结果,不阻断页面编辑。 + /// + public sealed class FundManagerLookupService + { + private sealed class FundManagerRow + { + public string InvestAdvisorCode { get; set; } + public string InvestAdvisorName { get; set; } + } + + private const string LookupSql = @" +SELECT + ia.investadvisorcode AS InvestAdvisorCode, + ia.investadvisorname AS InvestAdvisorName +FROM glms_bigdata.mf_fundarchives AS fa +INNER JOIN glms_bigdata.mf_investadvisoroutline AS ia + ON CONVERT(fa.investadvisorcode USING utf8mb4) COLLATE utf8mb4_unicode_ci = + CONVERT(ia.investadvisorcode USING utf8mb4) COLLATE utf8mb4_unicode_ci +WHERE CONVERT(fa.secucode USING utf8mb4) COLLATE utf8mb4_unicode_ci = + CONVERT(TRIM(SUBSTRING_INDEX(@UnderlyingCode, '.', 1)) USING utf8mb4) COLLATE utf8mb4_unicode_ci"; + + public FundManagerLookupResult Lookup(string underlyingCode) + { + var normalizedCode = NormalizeCode(underlyingCode); + if (string.IsNullOrEmpty(normalizedCode)) + { + return new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound }; + } + + var connectionString = AppManager.GetConnectionString("glms_bigdata"); + if (string.IsNullOrWhiteSpace(connectionString)) + { + return new FundManagerLookupResult { Status = FundManagerLookupStatus.Unavailable }; + } + + try + { + using var connection = new MySqlConnection(connectionString); + var matches = connection.Query(LookupSql, new { UnderlyingCode = normalizedCode }, commandTimeout: 10) + .Where(row => !string.IsNullOrWhiteSpace(row.InvestAdvisorName)) + .GroupBy(row => (row.InvestAdvisorCode ?? string.Empty).Trim(), StringComparer.OrdinalIgnoreCase) + .Select(group => group.Select(row => row.InvestAdvisorName.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).ToArray()) + .Where(names => names.Length > 0) + .ToArray(); + + return matches.Length switch + { + 0 => new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound }, + 1 when matches[0].Length == 1 => new FundManagerLookupResult { Status = FundManagerLookupStatus.Unique, InvestAdvisorName = matches[0][0] }, + _ => new FundManagerLookupResult { Status = FundManagerLookupStatus.Multiple } + }; + } + catch (Exception ex) + { + LogFactory.GetLogger().Error("查询基金管理人失败,代码:" + normalizedCode, ex); + return new FundManagerLookupResult { Status = FundManagerLookupStatus.Unavailable }; + } + } + + public static string NormalizeCode(string underlyingCode) + { + var trimmed = underlyingCode?.Trim(); + if (string.IsNullOrEmpty(trimmed)) + { + return null; + } + + var dotIndex = trimmed.IndexOf('.'); + return (dotIndex < 0 ? trimmed : trimmed.Substring(0, dotIndex)).TrimToNull(); + } + } +} diff --git a/YLErpWeb/Controllers/underlying_managerController.cs b/YLErpWeb/Controllers/underlying_managerController.cs index 69ba8b66..fa9e7f35 100644 --- a/YLErpWeb/Controllers/underlying_managerController.cs +++ b/YLErpWeb/Controllers/underlying_managerController.cs @@ -525,6 +525,25 @@ namespace YLErp.Web.Controllers return JsonSuccess("", underlying); } + /// + /// 查询上游基金档案中的基金管理人。查询失败或结果不唯一时返回可降级结果。 + /// + [HttpGet] + public JsonResult GetFundManager(string code, string instrumentType) + { + if (!string.Equals(instrumentType, ConsGlobal.InstrumentType.Fund, StringComparison.OrdinalIgnoreCase)) + { + return JsonSuccess("", new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound }); + } + + var result = new FundManagerLookupService().Lookup(code); + return JsonSuccess("", new + { + result.InvestAdvisorName, + IsUnique = result.Status == FundManagerLookupStatus.Unique + }); + } + /// /// 预付金参数 /// diff --git a/YLErpWeb/wwwroot/Scripts/app/underlying/underlyingedit.js b/YLErpWeb/wwwroot/Scripts/app/underlying/underlyingedit.js index dd80db28..6e66b379 100644 --- a/YLErpWeb/wwwroot/Scripts/app/underlying/underlyingedit.js +++ b/YLErpWeb/wwwroot/Scripts/app/underlying/underlyingedit.js @@ -17,6 +17,10 @@ const consSelect = ['MarketCode', 'UnderlyingInstrumentType', 'UnderlyingState', 'UnderlyingStatus', 'UpDownLimitType', 'EtfSubType']; var autoUpDownLimit, autoVariety; +var fundManagerLookupSeq = 0; +var fundManagerLookupTimer = null; +var fundManagerLookupXhr = null; +var fundManagerManualEdit = false; $(function () { @@ -46,6 +50,12 @@ $(function () { lookup: ylotc.varieties }); + $('#InvestAdvisorName').on('input', function () { + fundManagerManualEdit = true; + }); + + $('#UnderlyingCode').on('input', refreshFundManagerLookup); + for (var i = 1; i <= 5; i++) { let datas = ylotc.underlyingBlocks.filter(x => x.Group === i); let autoBlock = FastVue.autocomplete(document.getElementById('inputBlock' + i), { @@ -112,9 +122,57 @@ $(function () { break; } $('#editForm').removeClass("form-None form-Stock form-CommodityFutures form-CommoditySpot form-Bonds form-Fund").addClass("form-" + classType); + refreshFundManagerLookup(); }).trigger('change'); }); +function refreshFundManagerLookup() { + var requestSeq = ++fundManagerLookupSeq; + if (fundManagerLookupTimer) { + clearTimeout(fundManagerLookupTimer); + fundManagerLookupTimer = null; + } + if (fundManagerLookupXhr) { + fundManagerLookupXhr.abort(); + fundManagerLookupXhr = null; + } + + var codeInput = $('#UnderlyingCode'); + var typeInput = $('#UnderlyingInstrumentType'); + var managerInput = $('#InvestAdvisorName'); + if (page.Model.id > 0 || !codeInput.length || !typeInput.length || + typeInput.val() !== 'Fund' || !codeInput.val() || !managerInput.length) { + return; + } + + var codeAtRequest = codeInput.val(); + var managerAtRequest = managerInput.val() || ''; + var manualAtRequest = fundManagerManualEdit; + fundManagerLookupTimer = setTimeout(function () { + fundManagerLookupTimer = null; + fundManagerLookupXhr = $.ajax({ + url: '/underlying_manager/GetFundManager', + method: 'GET', + data: { code: codeAtRequest, instrumentType: 'Fund' } + }).done(function (resp) { + if (requestSeq !== fundManagerLookupSeq || page.Model.id > 0 || + $('#UnderlyingCode').val() !== codeAtRequest || + $('#UnderlyingInstrumentType').val() !== 'Fund' || + manualAtRequest || fundManagerManualEdit) { + return; + } + + var result = resp && resp.obj; + if (result && result.IsUnique && result.InvestAdvisorName) { + managerInput.val(result.InvestAdvisorName); + fundManagerManualEdit = false; + } + }).always(function () { + fundManagerLookupXhr = null; + }); + }, 200); +} + function saveData() { var data = $('#editForm').serializeObject();