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();