Files
zszq-trs/YLErpWeb/Controllers/EodPriceController.cs
T
hjhan 045361dd9b feat: 日终价格新增标的代码支持输入联想(服务端模糊匹配+原生下拉,防填错)
- 新增 SuggestUnderlyingForEod(code,kind):按代码/名称 LIKE 匹配、Take(20)、强制 LaunchState==1 与类型,与列表查询/Lookup 三处口径一致

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

- 不依赖任何前端自动补全插件(jQuery UI 未打包),可支撑几十万标的数据量
2026-07-13 13:25:19 +08:00

316 lines
13 KiB
C#

using YLErp.Core;
using YLErp.DBModels;
using YLErp.Modules.EodModule;
namespace YLErp.Web.Controllers
{
public class EodPriceController : BaseController
{
readonly IViewRenderService _viewRenderer;
public EodPriceController(IViewRenderService viewRenderer)
{
_viewRenderer = viewRenderer;
}
[MyAuthorize("结算管理-日终价格查看")]
public ActionResult EodPriceList()
{
return View();
}
[HttpPost]
public JsonResult EodPriceQuery(EodCommodityFuturePriceReq req)
{
var sList = new EodPriceService(CurUser).SearchUnderlyingList(req);
return Json(sList);
}
public ActionResult EodPriceView(string enid, string UnderlyingInstrumentType)
{
var eodUnderlying = new EodPriceViewModel() { UnderlyingInstrumentType = UnderlyingInstrumentType };
var intid = DecryptLong(enid);
if ("Stock".Equals(UnderlyingInstrumentType))
{
var id = Convert.ToInt32(intid);
var r = yldb.eod_stock_price.Find(id);
eodUnderlying.eod_Stock_Price = r;
eodUnderlying.underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(r.UnderlyingCode);
}
else if ("CommodityFutures".Equals(UnderlyingInstrumentType))
{
var id = Convert.ToInt32(intid);
var r = yldb.eod_commodity_future_price.Find(id);
eodUnderlying.eod_commodity_future_price = r;
eodUnderlying.underlying = yldb.underlying_manager.Find(r.UnderlyingId);
}
else
{
var r = yldb.china_bond_valuation.Find(intid);
eodUnderlying.ChinaBondValuation = r;
eodUnderlying.underlying = yldb.underlying_manager.FirstOrDefault(x => x.UnderlyingCode == r.bond_id);
}
return View(eodUnderlying);
}
public ActionResult EodFuturePriceEdit(string enid)
{
bool isNew = string.IsNullOrEmpty(enid) || enid == "0";
ViewBag.IsNew = isNew;
if (isNew)
{
// 新建:手工输入标的代码,失焦时调 LookupUnderlyingForEod 校验并带出市场/UnderlyingId。
// 默认估值日期=今天:避免未填日期时落库为 0001-01-01、落在列表默认窗口(今天)之外而查不出。
return View(new eod_commodity_future_price { ValueDate = DateTime.Today });
}
var intid = DecryptInt(enid);
var dbmodel = yldb.eod_commodity_future_price.Find(intid);
if (dbmodel == null)
{
return ShowError("找不到数据");
}
ViewData["市场"] = DataCacheProvider.GetUnderlyingDataSource().GetData(dbmodel.UnderlyingCode)?.MarketName;
return View(dbmodel);
}
public ActionResult EodStockPriceEdit(string enid)
{
bool isNew = string.IsNullOrEmpty(enid) || enid == "0";
ViewBag.IsNew = isNew;
if (isNew)
{
// 新建:手工输入标的代码,失焦时调 LookupUnderlyingForEod 校验并带出市场。
return View(new eod_stock_price { ValueDate = DateTime.Today });
}
var intid = DecryptInt(enid);
var dbmodel = yldb.eod_stock_price.Find(intid);
if (dbmodel == null)
{
return ShowError("找不到数据");
}
ViewData["市场"] = DataCacheProvider.GetUnderlyingDataSource().GetData(dbmodel.UnderlyingCode)?.MarketName;
return View(dbmodel);
}
public ActionResult EodBondPriceEdit(string enid)
{
bool isNew = string.IsNullOrEmpty(enid) || enid == "0";
ViewBag.IsNew = isNew;
if (isNew)
{
// 新建:手工输入债券代码(bond_id),失焦时调 LookupUnderlyingForEod 校验并带出市场。
// 默认估值日期=今天:避免未填日期时落库为 0001-01-01、落在列表默认窗口(今天)之外而查不出。
return View(new ChinaBondValuation { valuation_date = DateTime.Today });
}
var intid = DecryptLong(enid);
var dbmodel = yldb.china_bond_valuation.Find(intid);
if (dbmodel == null)
{
return ShowError("找不到数据");
}
ViewData["市场"] = DataCacheProvider.GetUnderlyingDataSource().GetData(dbmodel.bond_id)?.MarketName;
return View(dbmodel);
}
/// <summary>
/// 新建日终价格时,按用户手工输入的标的代码精确查一条标的,带出名称/市场/Id。
/// 只返回已上市(LaunchState=="1")且类型匹配的标的——与列表查询 inner join 的过滤对齐,
/// 从源头杜绝"新增能存但查不出"的幽灵记录。前端在输入框失焦时调用,不依赖任何下拉/补全插件。
/// </summary>
/// <param name="code">标的代码(用户手工输入)</param>
/// <param name="kind">bond | future | stock,决定允许的标的类型集合</param>
[HttpPost]
public JsonResult LookupUnderlyingForEod(string code, string kind)
{
if (string.IsNullOrWhiteSpace(code))
{
return JsonError("请输入标的代码");
}
code = code.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 u = yldb.underlying_manager
.Where(n => n.UnderlyingCode == code && n.LaunchState == "1" && set.Contains(n.UnderlyingInstrumentType))
.Select(n => new { n.id, n.UnderlyingCode, n.UnderlyingName, n.MarketName })
.FirstOrDefault();
if (u == null)
{
return JsonError("未找到该标的(不存在、未上市或类型不匹配),无法录入");
}
return JsonSuccess("", new
{
Id = u.id,
Code = u.UnderlyingCode,
Name = u.UnderlyingName,
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)
{
if (!string.IsNullOrEmpty(req.EncryptId))
{
req.id = DecryptInt(req.EncryptId);
}
var r = new EodPriceService(CurUser).SaveEodFuturePrice(req);
return JsonSuccess("更新成功", r);
}
public JsonResult EodBondPriceEditJson(ChinaBondValuation req)
{
if (!string.IsNullOrEmpty(req.EncryptId))
{
req.id = DecryptLong(req.EncryptId);
}
var r = new EodPriceService(CurUser).SaveBondPrice(req);
return JsonSuccess("更新成功", r);
}
[HttpPost]
public JsonResult EodStockPriceEditJson(eod_stock_price req)
{
if (!string.IsNullOrEmpty(req.EncryptId))
{
req.id = DecryptInt(req.EncryptId);
}
var r = new EodPriceService(CurUser).SaveEodStockPrice(req);
return JsonSuccess("更新成功", r);
}
[HttpPost]
public JsonResult DeletEodPrice(string id)
{
var intid = DecryptInt(id);
var r = yldb.eod_commodity_future_price.Find(intid);
if (r == null)
{
return JsonError("找不到日终商品期货价格");
}
yldb.eod_commodity_future_price.Remove(r);
yldb.SaveChanges();
return JsonSuccess("删除成功");
}
/// <summary>
/// 导入结算价
/// </summary>
public async Task<ActionResult> UploadSettlementBill(IFormFile file)
{
try
{
if (file == null || string.IsNullOrWhiteSpace(file.FileName))
{
return JsonError("未获取上传文件");
}
var fileExtension = Path.GetExtension(file.FileName);
if (fileExtension.ToLowerInvariant() != ".xlsx")
{
return JsonError("请上传xlsx格式的文件");
}
using var openStream = file.OpenReadStream();
var result = new SettlementPriceImportService(CurUser).ImportxlsxDatas(openStream);
var html = await _viewRenderer.RenderToStringAsync("Common/ImportResult", result);
return JsonSuccess(null, html);
}
catch (Exception ex)
{
LogFactory.GetLogger("导入结算价").Error("导入结算价出错", ex);
return JsonError(ex.Message);
}
}
}
}