feat: 日终价格新增标的代码支持输入联想(服务端模糊匹配+原生下拉,防填错)

- 新增 SuggestUnderlyingForEod(code,kind):按代码/名称 LIKE 匹配、Take(20)、强制 LaunchState==1 与类型,与列表查询/Lookup 三处口径一致

- 三个编辑页代码输入框加 oninput 防抖联想,原生 fixed 下拉展示候选,点选回填精确代码并复用失焦校验带出市场;期货额外回填 UnderlyingId

- 不依赖任何前端自动补全插件(jQuery UI 未打包),可支撑几十万标的数据量
This commit is contained in:
hjhan
2026-07-13 13:25:19 +08:00
parent 2ade7b46bb
commit 045361dd9b
4 changed files with 232 additions and 3 deletions
@@ -176,6 +176,63 @@ namespace YLErp.Web.Controllers
Market = u.MarketName,
});
}
/// <summary>
/// 新建日终价格时,按手工输入的片段做服务端模糊联想(代码或名称包含匹配),只回前 20 条。
/// 与 LookupUnderlyingForEod 同样只返回已上市(LaunchState=="1")且类型匹配的标的。
/// 用原生下拉渲染(不依赖 jQuery UI,bundle 未打包),避免几十万标的全量渲染卡死。
/// </summary>
[HttpPost]
public JsonResult SuggestUnderlyingForEod(string q, string kind)
{
if (string.IsNullOrWhiteSpace(q))
{
return JsonSuccess("", new List<object>());
}
q = q.Trim();
string[] types = kind switch
{
"future" => new[]
{
ConsGlobal.InstrumentType.CommodityFutures,
ConsGlobal.InstrumentType.GoldFutures,
ConsGlobal.InstrumentType.TBFutures,
ConsGlobal.InstrumentType.OtherFutures,
ConsGlobal.InstrumentType.AbroadFutures,
},
"stock" => new[]
{
ConsGlobal.InstrumentType.Stock,
ConsGlobal.InstrumentType.StockIndex,
ConsGlobal.InstrumentType.StockIF,
ConsGlobal.InstrumentType.HKStock,
ConsGlobal.InstrumentType.HKStockIndex,
ConsGlobal.InstrumentType.NewOtcStock,
ConsGlobal.InstrumentType.AbroadStock,
ConsGlobal.InstrumentType.AbroadStockIndex,
},
_ => new[]
{
ConsGlobal.InstrumentType.Bonds,
ConsGlobal.InstrumentType.TBonds,
ConsGlobal.InstrumentType.CreditBonds,
ConsGlobal.InstrumentType.OtherBonds,
},
};
var set = new HashSet<string>(types);
var list = yldb.underlying_manager
.Where(n => n.LaunchState == "1" && set.Contains(n.UnderlyingInstrumentType)
&& (n.UnderlyingCode.Contains(q) || n.UnderlyingName.Contains(q)))
.OrderBy(n => n.UnderlyingCode)
.Take(20)
.Select(n => new { n.id, Code = n.UnderlyingCode, Name = n.UnderlyingName, Market = n.MarketName })
.ToList();
return JsonSuccess("", list);
}
[HttpPost]
public JsonResult EodFuturePriceEditJson(eod_commodity_future_price req)
{
@@ -43,6 +43,63 @@
});
}
// 服务端模糊联想:输入时按需查前20条匹配(代码或名称),原生下拉,不用插件
var _eodSuggestTimer = null;
function eodSuggest(input, kind) {
clearTimeout(_eodSuggestTimer);
var q = (input.value || '').trim();
if (q.length < 1) { eodHideSuggest(); return; }
_eodSuggestTimer = setTimeout(function () {
main.post('/eodPrice/SuggestUnderlyingForEod', { q: q, kind: kind }).done(function (res) {
if (res.success && res.obj && res.obj.length) {
eodRenderSuggest(res.obj, input, kind);
} else {
eodHideSuggest();
}
});
}, 250);
}
function eodRenderSuggest(list, input, kind) {
var box = document.getElementById('eodSuggestBox');
if (!box) return;
box.innerHTML = '';
list.forEach(function (item) {
var div = document.createElement('div');
div.className = 'eod-suggest-item';
var code = document.createElement('span');
code.className = 'eod-suggest-code';
code.textContent = item.Code;
var name = document.createElement('span');
name.className = 'eod-suggest-name';
name.textContent = item.Name || '';
div.appendChild(code); div.appendChild(name);
div.onmousedown = function (e) {
e.preventDefault();
input.value = item.Code;
eodHideSuggest();
var fn = { bond: lookupBond, future: lookupFuture, stock: lookupStock }[kind];
if (fn) fn();
};
box.appendChild(div);
});
var r = input.getBoundingClientRect();
box.style.left = r.left + 'px';
box.style.top = (r.bottom + 2) + 'px';
box.style.width = Math.max(r.width, 220) + 'px';
box.style.display = 'block';
}
function eodHideSuggest() {
var b = document.getElementById('eodSuggestBox');
if (b) b.style.display = 'none';
}
document.addEventListener('click', function (e) {
var b = document.getElementById('eodSuggestBox');
if (b && b.style.display === 'block' && !b.contains(e.target)
&& e.target.id !== 'bond_id' && e.target.id !== 'UnderlyingCode') {
b.style.display = 'none';
}
});
</script>
}
<form class="yc-panel" id="form1" method="post" onsubmit="return false;">
@@ -62,7 +119,7 @@
{
<div class='form-group col-md-6'>
<label class='formlabel'>标的代码</label>
<input class='text-box' type='text' id="bond_id" name="bond_id" value="" onblur="lookupBond()" placeholder="输入债券代码,失焦自动带出市场" />
<input class='text-box' type='text' id="bond_id" name="bond_id" value="" onblur="lookupBond()" oninput="eodSuggest(this, 'bond')" placeholder="输入债券代码(边打边联想),失焦自动带出市场" />
</div>
<div class='form-group col-md-6'>
<label class='formlabel'>市场</label>
@@ -49,6 +49,63 @@
});
}
// 服务端模糊联想:输入时按需查前20条匹配(代码或名称),原生下拉,不用插件
var _eodSuggestTimer = null;
function eodSuggest(input, kind) {
clearTimeout(_eodSuggestTimer);
var q = (input.value || '').trim();
if (q.length < 1) { eodHideSuggest(); return; }
_eodSuggestTimer = setTimeout(function () {
main.post('/eodPrice/SuggestUnderlyingForEod', { q: q, kind: kind }).done(function (res) {
if (res.success && res.obj && res.obj.length) {
eodRenderSuggest(res.obj, input, kind);
} else {
eodHideSuggest();
}
});
}, 250);
}
function eodRenderSuggest(list, input, kind) {
var box = document.getElementById('eodSuggestBox');
if (!box) return;
box.innerHTML = '';
list.forEach(function (item) {
var div = document.createElement('div');
div.className = 'eod-suggest-item';
var code = document.createElement('span');
code.className = 'eod-suggest-code';
code.textContent = item.Code;
var name = document.createElement('span');
name.className = 'eod-suggest-name';
name.textContent = item.Name || '';
div.appendChild(code); div.appendChild(name);
div.onmousedown = function (e) {
e.preventDefault();
input.value = item.Code;
eodHideSuggest();
var fn = { bond: lookupBond, future: lookupFuture, stock: lookupStock }[kind];
if (fn) fn();
};
box.appendChild(div);
});
var r = input.getBoundingClientRect();
box.style.left = r.left + 'px';
box.style.top = (r.bottom + 2) + 'px';
box.style.width = Math.max(r.width, 220) + 'px';
box.style.display = 'block';
}
function eodHideSuggest() {
var b = document.getElementById('eodSuggestBox');
if (b) b.style.display = 'none';
}
document.addEventListener('click', function (e) {
var b = document.getElementById('eodSuggestBox');
if (b && b.style.display === 'block' && !b.contains(e.target)
&& e.target.id !== 'bond_id' && e.target.id !== 'UnderlyingCode') {
b.style.display = 'none';
}
});
</script>
}
<form class="yc-panel" id="form1" method="post" onsubmit="return false;">
@@ -74,7 +131,7 @@
{
<div class='form-group col-md-6'>
<label class='formlabel'>标的代码</label>
<input class='text-box' type='text' id="UnderlyingCode" name="UnderlyingCode" value="" onblur="lookupFuture()" placeholder="输入期货合约代码,失焦自动带出市场" />
<input class='text-box' type='text' id="UnderlyingCode" name="UnderlyingCode" value="" onblur="lookupFuture()" oninput="eodSuggest(this, 'future')" placeholder="输入期货合约代码(边打边联想),失焦自动带出市场" />
</div>
<div class='form-group col-md-6'>
<label class='formlabel'>市场</label>
@@ -42,6 +42,64 @@
main.parentReloadData();
});
}
// 服务端模糊联想:输入时按需查前20条匹配(代码或名称),原生下拉,不用插件
var _eodSuggestTimer = null;
function eodSuggest(input, kind) {
clearTimeout(_eodSuggestTimer);
var q = (input.value || '').trim();
if (q.length < 1) { eodHideSuggest(); return; }
_eodSuggestTimer = setTimeout(function () {
main.post('/eodPrice/SuggestUnderlyingForEod', { q: q, kind: kind }).done(function (res) {
if (res.success && res.obj && res.obj.length) {
eodRenderSuggest(res.obj, input, kind);
} else {
eodHideSuggest();
}
});
}, 250);
}
function eodRenderSuggest(list, input, kind) {
var box = document.getElementById('eodSuggestBox');
if (!box) return;
box.innerHTML = '';
list.forEach(function (item) {
var div = document.createElement('div');
div.className = 'eod-suggest-item';
var code = document.createElement('span');
code.className = 'eod-suggest-code';
code.textContent = item.Code;
var name = document.createElement('span');
name.className = 'eod-suggest-name';
name.textContent = item.Name || '';
div.appendChild(code); div.appendChild(name);
div.onmousedown = function (e) {
e.preventDefault();
input.value = item.Code;
eodHideSuggest();
var fn = { bond: lookupBond, future: lookupFuture, stock: lookupStock }[kind];
if (fn) fn();
};
box.appendChild(div);
});
var r = input.getBoundingClientRect();
box.style.left = r.left + 'px';
box.style.top = (r.bottom + 2) + 'px';
box.style.width = Math.max(r.width, 220) + 'px';
box.style.display = 'block';
}
function eodHideSuggest() {
var b = document.getElementById('eodSuggestBox');
if (b) b.style.display = 'none';
}
document.addEventListener('click', function (e) {
var b = document.getElementById('eodSuggestBox');
if (b && b.style.display === 'block' && !b.contains(e.target)
&& e.target.id !== 'bond_id' && e.target.id !== 'UnderlyingCode') {
b.style.display = 'none';
}
});
</script>
}
<form class="yc-panel" id="form1" method="post" onsubmit="return false;">
@@ -62,7 +120,7 @@
{
<div class='form-group col-md-6'>
<label class='formlabel'>标的代码</label>
<input class='text-box' type='text' id="UnderlyingCode" name="UnderlyingCode" value="" onblur="lookupStock()" placeholder="输入股票代码,失焦自动带出市场" />
<input class='text-box' type='text' id="UnderlyingCode" name="UnderlyingCode" value="" onblur="lookupStock()" oninput="eodSuggest(this, 'stock')" placeholder="输入股票代码(边打边联想),失焦自动带出市场" />
</div>
<div class='form-group col-md-6'>
<label class='formlabel'>市场</label>