Merge branch 'master' into wxw
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | namespace Admin.NET.Core; |
| | | |
| | | /// <summary> |
| | | /// 导出日志数据 |
| | | /// </summary> |
| | | [ExcelExporter(Name = "日志数据", TableStyle = OfficeOpenXml.Table.TableStyles.None, AutoFitAllColumn = true)] |
| | | public class ExportLogDto |
| | | { |
| | | /// <summary> |
| | | /// 记录器类别名称 |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "记录器类别名称", IsBold = true)] |
| | | public string LogName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 日志级别 |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "日志级别", IsBold = true)] |
| | | public string LogLevel { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 事件Id |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "事件Id", IsBold = true)] |
| | | public string EventId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 日志消息 |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "日志消息", IsBold = true)] |
| | | public string Message { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 异常对象 |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "异常对象", IsBold = true)] |
| | | public string Exception { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 当前状态值 |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "当前状态值", IsBold = true)] |
| | | public string State { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 日志记录时间 |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "日志记录时间", IsBold = true)] |
| | | public DateTime LogDateTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 线程Id |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "线程Id", IsBold = true)] |
| | | public int ThreadId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 请求跟踪Id |
| | | /// </summary> |
| | | [ExporterHeader(DisplayName = "请求跟踪Id", IsBold = true)] |
| | | public string TraceId { get; set; } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | namespace Admin.NET.Core.Service; |
| | | |
| | | public class PageOpLogInput : PageVisLogInput |
| | | { |
| | | /// <summary> |
| | | /// 模块名称 |
| | | /// </summary> |
| | | public string? ControllerName { get; set; } |
| | | } |
| | | |
| | | public class PageExLogInput : PageOpLogInput |
| | | { |
| | | } |
| | | |
| | | public class PageVisLogInput : PageLogInput |
| | | { |
| | | /// <summary> |
| | | /// 方法名称 |
| | | ///</summary> |
| | | public string? ActionName { get; set; } |
| | | } |
| | | |
| | | public class PageLogInput : BasePageInput |
| | | { |
| | | /// <summary> |
| | | /// 开始时间 |
| | | /// </summary> |
| | | public DateTime? StartTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 结束时间 |
| | | /// </summary> |
| | | public DateTime? EndTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 账号 |
| | | /// </summary> |
| | | public string? Account { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 操作用时 |
| | | /// </summary> |
| | | public long? Elapsed { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 状态 |
| | | /// </summary> |
| | | public string Status { get; set; } |
| | | |
| | | /// <summary> |
| | | /// IP地址 |
| | | /// </summary> |
| | | public string? RemoteIp { get; set; } |
| | | } |
| | | |
| | | public class LogInput |
| | | { |
| | | /// <summary> |
| | | /// 开始时间 |
| | | /// </summary> |
| | | public DateTime? StartTime { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 结束时间 |
| | | /// </summary> |
| | | public DateTime? EndTime { get; set; } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | namespace Admin.NET.Core.Service; |
| | | |
| | | public class LogVisOutput |
| | | { |
| | | /// <summary> |
| | | /// 登录地点 |
| | | /// </summary> |
| | | public string Location { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 经度 |
| | | /// </summary> |
| | | public double? Longitude { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 维度 |
| | | /// </summary> |
| | | public double? Latitude { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 真实姓名 |
| | | /// </summary> |
| | | public string RealName { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 日志时间 |
| | | /// </summary> |
| | | public DateTime? LogDateTime { get; set; } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | namespace Admin.NET.Core.Service; |
| | | |
| | | /// <summary> |
| | | /// 系统差异日志服务 🧩 |
| | | /// </summary> |
| | | [ApiDescriptionSettings(Order = 330)] |
| | | public class SysLogDiffService : IDynamicApiController, ITransient |
| | | { |
| | | private readonly SqlSugarRepository<SysLogDiff> _sysLogDiffRep; |
| | | |
| | | public SysLogDiffService(SqlSugarRepository<SysLogDiff> sysLogDiffRep) |
| | | { |
| | | _sysLogDiffRep = sysLogDiffRep; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取差异日志分页列表 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [SuppressMonitor] |
| | | [DisplayName("获取差异日志分页列表")] |
| | | public async Task<SqlSugarPagedList<SysLogDiff>> Page(PageLogInput input) |
| | | { |
| | | return await _sysLogDiffRep.AsQueryable() |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()), u => u.CreateTime >= input.StartTime) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.EndTime.ToString()), u => u.CreateTime <= input.EndTime) |
| | | .OrderBy(u => u.CreateTime, OrderByType.Desc) |
| | | .ToPagedListAsync(input.Page, input.PageSize); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取差异日志详情 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [SuppressMonitor] |
| | | [DisplayName("获取差异日志详情")] |
| | | public async Task<SysLogDiff> GetDetail(long id) |
| | | { |
| | | return await _sysLogDiffRep.GetFirstAsync(u => u.Id == id); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 清空差异日志 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [ApiDescriptionSettings(Name = "Clear"), HttpPost] |
| | | [DisplayName("清空差异日志")] |
| | | public void Clear() |
| | | { |
| | | _sysLogDiffRep.AsSugarClient().DbMaintenance.TruncateTable<SysLogDiff>(); |
| | | } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | namespace Admin.NET.Core.Service; |
| | | |
| | | /// <summary> |
| | | /// 系统异常日志服务 🧩 |
| | | /// </summary> |
| | | [ApiDescriptionSettings(Order = 350)] |
| | | public class SysLogExService : IDynamicApiController, ITransient |
| | | { |
| | | private readonly SqlSugarRepository<SysLogEx> _sysLogExRep; |
| | | |
| | | public SysLogExService(SqlSugarRepository<SysLogEx> sysLogExRep) |
| | | { |
| | | _sysLogExRep = sysLogExRep; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取异常日志分页列表 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [SuppressMonitor] |
| | | [DisplayName("获取异常日志分页列表")] |
| | | public async Task<SqlSugarPagedList<SysLogEx>> Page(PageExLogInput input) |
| | | { |
| | | return await _sysLogExRep.AsQueryable() |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()), u => u.CreateTime >= input.StartTime) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.EndTime.ToString()), u => u.CreateTime <= input.EndTime) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Account), u => u.Account == input.Account) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.ControllerName), u => u.ControllerName == input.ControllerName) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.ActionName), u => u.ActionName == input.ActionName) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.RemoteIp), u => u.RemoteIp == input.RemoteIp) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Elapsed.ToString()), u => u.Elapsed >= input.Elapsed) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Status) && input.Status == "200", u => u.Status == input.Status) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Status) && input.Status != "200", u => u.Status != input.Status) |
| | | //.OrderBy(u => u.CreateTime, OrderByType.Desc) |
| | | .IgnoreColumns(u => new { u.RequestParam, u.ReturnResult, u.Message }) |
| | | .OrderBuilder(input) |
| | | .ToPagedListAsync(input.Page, input.PageSize); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取异常日志详情 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [SuppressMonitor] |
| | | [DisplayName("获取异常日志详情")] |
| | | public async Task<SysLogEx> GetDetail(long id) |
| | | { |
| | | return await _sysLogExRep.GetFirstAsync(u => u.Id == id); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 清空异常日志 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [ApiDescriptionSettings(Name = "Clear"), HttpPost] |
| | | [DisplayName("清空异常日志")] |
| | | public void Clear() |
| | | { |
| | | _sysLogExRep.AsSugarClient().DbMaintenance.TruncateTable<SysLogEx>(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 导出异常日志 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [ApiDescriptionSettings(Name = "Export"), NonUnify] |
| | | [DisplayName("导出异常日志")] |
| | | public async Task<IActionResult> ExportLogEx(LogInput input) |
| | | { |
| | | var logExList = await _sysLogExRep.AsQueryable() |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()) && !string.IsNullOrWhiteSpace(input.EndTime.ToString()), |
| | | u => u.CreateTime >= input.StartTime && u.CreateTime <= input.EndTime) |
| | | .OrderBy(u => u.CreateTime, OrderByType.Desc) |
| | | .Select<ExportLogDto>().ToListAsync(); |
| | | |
| | | IExcelExporter excelExporter = new ExcelExporter(); |
| | | var res = await excelExporter.ExportAsByteArray(logExList); |
| | | return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "异常日志.xlsx" }; |
| | | } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | namespace Admin.NET.Core.Service; |
| | | |
| | | /// <summary> |
| | | /// 系统操作日志服务 🧩 |
| | | /// </summary> |
| | | [ApiDescriptionSettings(Order = 360)] |
| | | public class SysLogOpService : IDynamicApiController, ITransient |
| | | { |
| | | private readonly SqlSugarRepository<SysLogOp> _sysLogOpRep; |
| | | |
| | | public SysLogOpService(SqlSugarRepository<SysLogOp> sysLogOpRep) |
| | | { |
| | | _sysLogOpRep = sysLogOpRep; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取操作日志分页列表 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [SuppressMonitor] |
| | | [DisplayName("获取操作日志分页列表")] |
| | | public async Task<SqlSugarPagedList<SysLogOp>> Page(PageOpLogInput input) |
| | | { |
| | | return await _sysLogOpRep.AsQueryable() |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()), u => u.CreateTime >= input.StartTime) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.EndTime.ToString()), u => u.CreateTime <= input.EndTime) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Account), u => u.Account == input.Account) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.RemoteIp), u => u.RemoteIp == input.RemoteIp) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.ControllerName), u => u.ControllerName == input.ControllerName) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.ActionName), u => u.ActionName == input.ActionName) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Elapsed.ToString()), u => u.Elapsed >= input.Elapsed) |
| | | //.OrderBy(u => u.CreateTime, OrderByType.Desc) |
| | | .IgnoreColumns(u => new { u.RequestParam, u.ReturnResult, u.Message }) |
| | | .OrderBuilder(input) |
| | | .ToPagedListAsync(input.Page, input.PageSize); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取操作日志详情 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [SuppressMonitor] |
| | | [DisplayName("获取操作日志详情")] |
| | | public async Task<SysLogOp> GetDetail(long id) |
| | | { |
| | | return await _sysLogOpRep.GetFirstAsync(u => u.Id == id); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 清空操作日志 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [ApiDescriptionSettings(Name = "Clear"), HttpPost] |
| | | [DisplayName("清空操作日志")] |
| | | public void Clear() |
| | | { |
| | | _sysLogOpRep.AsSugarClient().DbMaintenance.TruncateTable<SysLogOp>(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 导出操作日志 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [ApiDescriptionSettings(Name = "Export"), NonUnify] |
| | | [DisplayName("导出操作日志")] |
| | | public async Task<IActionResult> ExportLogOp(LogInput input) |
| | | { |
| | | var logOpList = await _sysLogOpRep.AsQueryable() |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()) && !string.IsNullOrWhiteSpace(input.EndTime.ToString()), |
| | | u => u.CreateTime >= input.StartTime && u.CreateTime <= input.EndTime) |
| | | .OrderBy(u => u.CreateTime, OrderByType.Desc) |
| | | .Select<ExportLogDto>().ToListAsync(); |
| | | |
| | | IExcelExporter excelExporter = new ExcelExporter(); |
| | | var res = await excelExporter.ExportAsByteArray(logOpList); |
| | | return new FileStreamResult(new MemoryStream(res), "application/octet-stream") { FileDownloadName = DateTime.Now.ToString("yyyyMMddHHmm") + "操作日志.xlsx" }; |
| | | } |
| | | } |
New file |
| | |
| | | // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 |
| | | // |
| | | // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 |
| | | // |
| | | // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! |
| | | |
| | | namespace Admin.NET.Core.Service; |
| | | |
| | | /// <summary> |
| | | /// 系统访问日志服务 🧩 |
| | | /// </summary> |
| | | [ApiDescriptionSettings(Order = 340)] |
| | | public class SysLogVisService : IDynamicApiController, ITransient |
| | | { |
| | | private readonly SqlSugarRepository<SysLogVis> _sysLogVisRep; |
| | | |
| | | public SysLogVisService(SqlSugarRepository<SysLogVis> sysLogVisRep) |
| | | { |
| | | _sysLogVisRep = sysLogVisRep; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取访问日志分页列表 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [SuppressMonitor] |
| | | [DisplayName("获取访问日志分页列表")] |
| | | public async Task<SqlSugarPagedList<SysLogVis>> Page(PageVisLogInput input) |
| | | { |
| | | return await _sysLogVisRep.AsQueryable() |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.StartTime.ToString()), u => u.CreateTime >= input.StartTime) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.EndTime.ToString()), u => u.CreateTime <= input.EndTime) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Account), u => u.Account == input.Account) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.ActionName), u => u.ActionName == input.ActionName) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.RemoteIp), u => u.RemoteIp == input.RemoteIp) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Elapsed.ToString()), u => u.Elapsed >= input.Elapsed) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Status) && input.Status == "200", u => u.Status == input.Status) |
| | | .WhereIF(!string.IsNullOrWhiteSpace(input.Status) && input.Status != "200", u => u.Status != input.Status) |
| | | .OrderBy(u => u.CreateTime, OrderByType.Desc) |
| | | .ToPagedListAsync(input.Page, input.PageSize); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 清空访问日志 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [ApiDescriptionSettings(Name = "Clear"), HttpPost] |
| | | [DisplayName("清空访问日志")] |
| | | public void Clear() |
| | | { |
| | | _sysLogVisRep.AsSugarClient().DbMaintenance.TruncateTable<SysLogVis>(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取访问日志列表 🔖 |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | [DisplayName("获取访问日志列表")] |
| | | public async Task<List<LogVisOutput>> GetList() |
| | | { |
| | | return await _sysLogVisRep.AsQueryable() |
| | | .Where(u => u.Longitude > 0 && u.Longitude > 0) |
| | | .Select(u => new LogVisOutput |
| | | { |
| | | Location = u.Location, |
| | | Longitude = u.Longitude, |
| | | Latitude = u.Latitude, |
| | | RealName = u.RealName, |
| | | LogDateTime = u.LogDateTime |
| | | }).ToListAsync(); |
| | | } |
| | | } |
| | |
| | | public class PlcHub : Hub<IPlcHub> |
| | | { |
| | | private readonly IHubContext<PlcHub, IPlcHub> _plcHubContext; |
| | | |
| | | public PlcHub(IHubContext<PlcHub, IPlcHub> plcHubContext) |
| | | private readonly SysConfigService _sysConfigService; |
| | | public PlcHub(IHubContext<PlcHub, IPlcHub> plcHubContext, SysConfigService sysConfigService) |
| | | { |
| | | _plcHubContext = plcHubContext; |
| | | _sysConfigService = sysConfigService; |
| | | } |
| | | /// <summary> |
| | | /// 下发PLC连接状态 |
| | |
| | | PLCTaskAction.Init(); |
| | | else |
| | | PLCTaskAction.Stop(); |
| | | await _sysConfigService.UpdateConfigValue("sys_RunningState", context.BoRunningState.Value); |
| | | } |
| | | //脱机模式 |
| | | if (context.BoOffline.HasValue) |
| | | { |
| | | PLCTaskAction.boOffline = context.BoOffline.Value; |
| | | await _sysConfigService.UpdateConfigValue("sys_Offline", context.BoOffline.Value); |
| | | } |
| | | //自刷新 |
| | | if (context.BoRefresh.HasValue) |
| | | { |
| | | PLCTaskAction.boRefresh = context.BoRefresh.Value; |
| | | await _sysConfigService.UpdateConfigValue("sys_Refresh", context.BoRefresh.Value); |
| | | } |
| | | await _plcHubContext.Clients.All.UpdateService(new PLCServiceModel() { BoRunningState = PLCTaskAction.boRunningState, BoRefresh = PLCTaskAction.boRefresh, BoOffline = PLCTaskAction.boOffline }); |
| | | } |
| | | } |
| | |
| | | private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId); |
| | | private static readonly SysCacheService sysCacheService = App.GetRequiredService<SysCacheService>(); |
| | | private static readonly IHubContext<PlcHub, IPlcHub> _plcHubContext = App.GetService<IHubContext<PlcHub, IPlcHub>>(); |
| | | private static readonly SysConfigService _sysConfigService = App.GetService<SysConfigService>(); |
| | | |
| | | private static List<WcsPlc> listPlc = new List<WcsPlc>(); |
| | | private static List<WcsDevice> listPlcDevice = new List<WcsDevice>(); |
| | |
| | | { |
| | | //订阅事件 |
| | | DeviceValueChangeEvent += PLCService.OnChangeEvent; |
| | | boRunningState = _sysConfigService.GetConfigValue<bool>("sys_RunningState").Result; |
| | | boOffline = _sysConfigService.GetConfigValue<bool>("sys_Offline").Result; |
| | | boRefresh = _sysConfigService.GetConfigValue<bool>("sys_Refresh").Result; |
| | | } |
| | | /// <summary> |
| | | /// 初始化PLC连接 |
| | |
| | | var plc = new PLCUtil(modPlc); |
| | | listPlcUtil.Add(plc); |
| | | } |
| | | cts = new CancellationTokenSource(); |
| | | boRunningState = true; |
| | | _plcHubContext.Clients.All.UpdateService(new PLCServiceModel() |
| | | { |
| | | BoRunningState = boRunningState, |
| | | BoOffline = boOffline, |
| | | BoRefresh = boRefresh |
| | | }); |
| | | StartRead(); |
| | | ConnectionStatus(); |
| | | StartWatchAlarm(); |
| | | StartWatchPosition(); |
| | | if (boRunningState) |
| | | { |
| | | cts = new CancellationTokenSource(); |
| | | StartRead(); |
| | | ConnectionStatus(); |
| | | StartWatchAlarm(); |
| | | StartWatchPosition(); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 开启读取plc线程 |
| | |
| | | address = DbNumber + "." + Pos; |
| | | else |
| | | address = DbNumber + Pos; |
| | | return this.GetPlcDBValue(PosType, address, Length); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 读取PLC值 |
| | | /// </summary> |
| | | /// <param name="PosType">字符类型</param> |
| | | /// <param name="Pos">偏移量/地址</param> |
| | | /// <param name="Length">长度(字符串)</param> |
| | | /// <returns></returns> |
| | | public (IoTClient.Result, dynamic value) GetPlcDBValue(PLCDataTypeEnum PosType, string Pos, int? Length = 0) |
| | | { |
| | | lock (OLock) |
| | | { |
| | | dynamic result = null; |
| | | switch (PosType) |
| | | { |
| | | case PLCDataTypeEnum.Bit: |
| | | result = _client.ReadBoolean(address); |
| | | result = _client.ReadBoolean(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.Byte: |
| | | result = _client.ReadByte(address); |
| | | result = _client.ReadByte(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.Short: |
| | | result = _client.ReadInt16(address); |
| | | result = _client.ReadInt16(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.UShort: |
| | | result = _client.ReadUInt16(address); |
| | | result = _client.ReadUInt16(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.Int: |
| | | result = _client.ReadInt32(address); |
| | | result = _client.ReadInt32(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.UInt: |
| | | result = _client.ReadUInt32(address); |
| | | result = _client.ReadUInt32(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.Long: |
| | | result = _client.ReadInt64(address); |
| | | result = _client.ReadInt64(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.ULong: |
| | | result = _client.ReadUInt64(address); |
| | | result = _client.ReadUInt64(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.Float: |
| | | result = _client.ReadFloat(address); |
| | | result = _client.ReadFloat(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.Double: |
| | | result = _client.ReadDouble(address); |
| | | result = _client.ReadDouble(Pos); |
| | | break; |
| | | case PLCDataTypeEnum.String: |
| | | result = _client.ReadString(address, Convert.ToUInt16(Length)); |
| | | result = _client.ReadString(Pos, Convert.ToUInt16(Length)); |
| | | break; |
| | | default: |
| | | result = new IoTClient.Result<object>(); |
| | |
| | | address = DbNumber + "." + Pos; |
| | | else |
| | | address = DbNumber + Pos; |
| | | return this.SetPlcDBValue(PosType, address, Pos, Value); |
| | | } |
| | | /// <summary> |
| | | /// 写入PLC值 |
| | | /// </summary> |
| | | public IoTClient.Result SetPlcDBValue(PLCDataTypeEnum PosType, string Pos, string Value) |
| | | { |
| | | switch (PosType) |
| | | { |
| | | case PLCDataTypeEnum.Bit: |
| | |
| | | throw new Exception("写入值错误"); |
| | | } |
| | | } |
| | | return _client.Write(address, bit); |
| | | return _client.Write(Pos, bit); |
| | | case PLCDataTypeEnum.Byte: |
| | | return _client.Write(address, byte.Parse(Value)); |
| | | return _client.Write(Pos, byte.Parse(Value)); |
| | | case PLCDataTypeEnum.Short: |
| | | return _client.Write(address, short.Parse(Value)); |
| | | return _client.Write(Pos, short.Parse(Value)); |
| | | case PLCDataTypeEnum.UShort: |
| | | return _client.Write(address, ushort.Parse(Value)); |
| | | return _client.Write(Pos, ushort.Parse(Value)); |
| | | case PLCDataTypeEnum.Int: |
| | | return _client.Write(address, int.Parse(Value)); |
| | | return _client.Write(Pos, int.Parse(Value)); |
| | | case PLCDataTypeEnum.UInt: |
| | | return _client.Write(address, uint.Parse(Value)); |
| | | return _client.Write(Pos, uint.Parse(Value)); |
| | | case PLCDataTypeEnum.Long: |
| | | return _client.Write(address, long.Parse(Value)); |
| | | return _client.Write(Pos, long.Parse(Value)); |
| | | case PLCDataTypeEnum.ULong: |
| | | return _client.Write(address, ulong.Parse(Value)); |
| | | return _client.Write(Pos, ulong.Parse(Value)); |
| | | case PLCDataTypeEnum.Float: |
| | | return _client.Write(address, float.Parse(Value)); |
| | | return _client.Write(Pos, float.Parse(Value)); |
| | | case PLCDataTypeEnum.Double: |
| | | return _client.Write(address, float.Parse(Value)); |
| | | return _client.Write(Pos, float.Parse(Value)); |
| | | default: |
| | | return new IoTClient.Result(); |
| | | } |
| | |
| | | |
| | | _sysCacheService.Remove($"{CacheConst.KeyConfig}{config.Code}"); |
| | | } |
| | | /// <summary> |
| | | /// 更新参数配置值 |
| | | /// </summary> |
| | | /// <param name="code"></param> |
| | | /// <param name="value"></param> |
| | | /// <returns></returns> |
| | | [NonAction] |
| | | public async Task UpdateConfigValue(string code, bool value) |
| | | { |
| | | var config = await _sysConfigRep.GetFirstAsync(u => u.Code == code); |
| | | if (config == null) return; |
| | | |
| | | config.Value = value?"True":"False"; |
| | | await _sysConfigRep.AsUpdateable(config).ExecuteCommandAsync(); |
| | | |
| | | _sysCacheService.Remove($"{CacheConst.KeyConfig}{config.Code}"); |
| | | } |
| | | } |
| | |
| | | { |
| | | |
| | | } |
| | | |
| | | public class ResetInput |
| | | { |
| | | [Required(ErrorMessage = "楼层不能为空")] |
| | | public int layer { get; set; } |
| | | } |
| | |
| | | using Microsoft.AspNetCore.SignalR; |
| | | using Admin.NET.Core.Service; |
| | | using Microsoft.AspNetCore.SignalR; |
| | | |
| | | namespace WCS.Application; |
| | | |
| | |
| | | { |
| | | private readonly SqlSugarRepository<WcsAlarmInfo> _wcsAlarmInfoRep; |
| | | private readonly IHubContext<PlcHub, IPlcHub> _plcHubContext; |
| | | public WcsAlarmInfoService(SqlSugarRepository<WcsAlarmInfo> wcsAlarmInfoRep, IHubContext<PlcHub, IPlcHub> plcHubContext) |
| | | private readonly SysDictDataService _dictDataService; |
| | | public WcsAlarmInfoService(SqlSugarRepository<WcsAlarmInfo> wcsAlarmInfoRep, IHubContext<PlcHub, IPlcHub> plcHubContext, SysDictDataService dictDataService) |
| | | { |
| | | _wcsAlarmInfoRep = wcsAlarmInfoRep; |
| | | _plcHubContext = plcHubContext; |
| | | _dictDataService = dictDataService; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | [HttpPost] |
| | | [ApiDescriptionSettings(Name = "Reset")] |
| | | [DisplayName("复位报警")] |
| | | public async Task Reset() |
| | | public async Task Reset(ResetInput input) |
| | | { |
| | | //测试推数据用的 |
| | | await _plcHubContext.Clients.All.PublicAlarm(new List<WcsAlarmInfo>() { new WcsAlarmInfo() { Id = 100, StationNum = "260", AlarmCode = "MB102", AlarmName = "有物品遮挡", AlarmTime = DateTime.Now, Status = YesNoEnum.N } }); |
| | | //await _plcHubContext.Clients.All.PublicAlarm(new List<WcsAlarmInfo>() { new WcsAlarmInfo() { Id = 100, StationNum = "260", AlarmCode = "MB102", AlarmName = "有物品遮挡", AlarmTime = DateTime.Now, Status = YesNoEnum.Y } }); |
| | | //await _plcHubContext.Clients.All.PublicAlarm(new WcsAlarmInfo() { Id = 100, StationNum = "260", AlarmCode = "MB102", AlarmName = "有物品遮挡", AlarmTime = DateTime.Now, Status = YesNoEnum.Y }); |
| | | var modPlc = await _wcsAlarmInfoRep.Context.Queryable<WcsPlc>().Where(s => s.Type == PLCTypeEnum.ConveyorLine && s.Text == (input.layer.ToString() + "层托盘输送线")).FirstAsync(); |
| | | if (modPlc == null) |
| | | throw Oops.Bah("未找到输送线PLC"); |
| | | var listDict = await _dictDataService.GetDataList("reset_alarm"); |
| | | var value = listDict.FirstOrDefault(s => s.Code == input.layer.ToString()); |
| | | if (value == null) |
| | | throw Oops.Bah("未找到复位地址,请在字典管理中设置"); |
| | | PLCUtil modUtil = new PLCUtil(modPlc); |
| | | switch (input.layer) |
| | | { |
| | | case 1: |
| | | break; |
| | | case 2: |
| | | { |
| | | modUtil.SetPlcDBValue(PLCDataTypeEnum.Bit, value.Value, "1"); |
| | | } |
| | | break; |
| | | case 3: |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | modUtil.Close(); |
| | | |
| | | //throw Oops.Bah("开发中"); |
| | | } |
| | | |
| | | |
| | |
| | | </el-col> |
| | | <el-col :span="19"> |
| | | <div class="card-page"> |
| | | <el-button type="primary" :plain="isPlain1" @click="floorTogglePlain(1)">一层平面</el-button> |
| | | <el-button type="primary" :plain="isPlain2" @click="floorTogglePlain(2)">二层平面</el-button> |
| | | <el-button type="primary" :plain="isPlain3" @click="floorTogglePlain(3)">三层平面</el-button> |
| | | <el-button type="primary" :plain="layer != 1" @click="floorTogglePlain(1)">一层平面</el-button> |
| | | <el-button type="primary" :plain="layer != 2" @click="floorTogglePlain(2)">二层平面</el-button> |
| | | <el-button type="primary" :plain="layer != 3" @click="floorTogglePlain(3)">三层平面</el-button> |
| | | </div> |
| | | <div style="margin: 40px; height: 50%;"> |
| | | <div class="grid-container-line"> |
| | |
| | | import 'splitpanes/dist/splitpanes.css'; |
| | | import { listWcsAlarmInfo, resetWcsAlarmInfo } from '/@/api/wcs/wcsAlarmInfo'; |
| | | import { signalR } from './signalR'; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | //连接signalR 监听变更 |
| | | onMounted(async () => { |
| | | signalR.off('PublicAlarm'); |
| | |
| | | |
| | | //复位报警 |
| | | const reset = async () => { |
| | | await resetWcsAlarmInfo(); |
| | | await resetWcsAlarmInfo({ layer: layer.value }); |
| | | ElMessage.success("复位成功"); |
| | | // await handleQuery(); |
| | | } |
| | | |
| | | |
| | | const isPlain1 = ref(false);//一层 |
| | | const isPlain2 = ref(true);//二层 |
| | | const isPlain3 = ref(true);//三层 |
| | | const layer = ref(1); |
| | | //切换层平面 |
| | | function floorTogglePlain(buttonNumber) { |
| | | layer.value = buttonNumber; |
| | | if (buttonNumber === 1) { |
| | | isPlain1.value = false; |
| | | isPlain2.value = true; |
| | | isPlain3.value = true; |
| | | //切换输送线数据 |
| | | cellsData.value = cellsDataOne.value; |
| | | } else if (buttonNumber === 2) { |
| | | isPlain2.value = false; |
| | | isPlain1.value = true; |
| | | isPlain3.value = true; |
| | | //切换输送线数据 |
| | | cellsData.value = cellsDataTwo.value; |
| | | } else if (buttonNumber === 3) { |
| | | isPlain3.value = false; |
| | | isPlain1.value = true; |
| | | isPlain2.value = true; |
| | | //切换输送线数据 |
| | | cellsData.value = cellsDataThree.value; |
| | | } |
New file |
| | |
| | | <template> |
| | | <div class="wcsAlarmInfo-container"> |
| | | <el-dialog v-model="isShowDialog" :width="800" draggable="" :close-on-click-modal="false"> |
| | | <template #header> |
| | | <div class="dialog-header"> |
| | | <span>{{ props.title }}</span> |
| | | </div> |
| | | </template> |
| | | |
| | | <el-card class="box-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | |
| | | <div> |
| | | <span>工位号:</span> |
| | | <el-select v-model="stationValue" placeholder="请选择" filterable value-key="stationNum" |
| | | style="width: 200px;"> |
| | | <el-option v-for="item in listStationsData" :key="item.id" :label="item.stationNum" |
| | | :value="item"> |
| | | </el-option> |
| | | </el-select> |
| | | <el-button style="margin-left: 10px;">自动</el-button> |
| | | </div> |
| | | <div> |
| | | <div :class="['lineStatus', stationValue.status ? 'device-status-0' : 'device-status-1']"></div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <div> |
| | | <el-form label-position="left" label-width="80px"> |
| | | <el-row :gutter="25"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="起始工位"> |
| | | <el-input v-model="stationValue.startLocatNo"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="目的工位"> |
| | | <el-input v-model="stationValue.endLocatNo"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="PLC"> |
| | | <el-input v-model="stationValue.plc"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="WCS"> |
| | | <el-input v-model="stationValue.wcs"></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | <el-col :span="12"> |
| | | <el-form-item label="取货排"> |
| | | <el-input ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="放货排"> |
| | | <el-input ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="取货列"> |
| | | <el-input ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="放货列"> |
| | | <el-input ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="取货层"> |
| | | <el-input ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="放货层"> |
| | | <el-input ></el-input> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <div style="text-align: center;margin: 10px;"> |
| | | <el-button class="button" size="large">写入数据</el-button> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="card-footer"> |
| | | <el-button class="button" size="large">正 转</el-button> |
| | | <el-button class="button" size="large">反 转</el-button> |
| | | <el-button class="button" size="large">移栽上升</el-button> |
| | | <el-button class="button" size="large">移栽下降</el-button> |
| | | </div> |
| | | </template> |
| | | </el-card> |
| | | |
| | | <!-- <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="closeDialog" type="primary">关 闭</el-button> |
| | | </span> |
| | | </template> --> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | | import { ref, defineModel } from 'vue'; |
| | | const listStationsData = defineModel<any>("listStationsData") |
| | | const stationValue = defineModel<any>("stationValue") |
| | | |
| | | const props = defineProps({ |
| | | title: { |
| | | type: String, |
| | | default: '', |
| | | } |
| | | }); |
| | | // const emit = defineEmits<{ (e: "update:listStationsData", value: Array<any>): void, (e: "update:stationValue", value): void }>() |
| | | |
| | | // const handlestationChange = () => { |
| | | // emit('update:listStationsData', listStationsData.value); |
| | | // emit('update:stationValue', stationValue); |
| | | // }; |
| | | |
| | | const isShowDialog = ref(false); |
| | | |
| | | const openDialog = async (row: any) => { |
| | | console.log(listStationsData.value); |
| | | debugger; |
| | | isShowDialog.value = true; |
| | | }; |
| | | |
| | | const closeDialog = () => { |
| | | isShowDialog.value = false; |
| | | }; |
| | | |
| | | defineExpose({ openDialog }); |
| | | </script> |
| | | |
| | | <style> |
| | | .el-col { |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | color: #fff; |
| | | padding: 10px; |
| | | border-radius: 10px 10px 0 0; |
| | | } |
| | | |
| | | .card-footer { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .text { |
| | | font-size: 14px; |
| | | color: #fff; |
| | | } |
| | | |
| | | .item { |
| | | margin-bottom: 18px; |
| | | } |
| | | |
| | | .box-card { |
| | | width: 100%; |
| | | background: linear-gradient(135deg, #66ccff, #3399ff); |
| | | border-radius: 10px; |
| | | color: #fff; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | padding: 10px; |
| | | } |
| | | |
| | | .lineStatus { |
| | | right: 0; |
| | | height: 20px; |
| | | width: 20px; |
| | | border-radius: 50%; |
| | | background-color: #67C23A; |
| | | } |
| | | |
| | | .device-status-0 { |
| | | background-color: #67C23A; |
| | | } |
| | | |
| | | .device-status-1 { |
| | | background-color: red; |
| | | } |
| | | </style> |
| | |
| | | <el-option v-for="item in lineOptions" :key="item.id" :label="item.text" |
| | | :value="item.id"></el-option> |
| | | </el-select> |
| | | <el-select v-model="stationValue" placeholder="请选择" style="margin-top: 10px;" |
| | | <el-select v-model="stationValue" placeholder="请选择" style="margin-top: 10px;" filterable |
| | | value-key="stationNum"> |
| | | <el-option v-for="item in listStationsData" :key="item.id" :label="item.stationNum" |
| | | :value="item"> |
| | |
| | | <el-form label-position="left" label-width="80px"> |
| | | <el-form-item> |
| | | <el-button>写入</el-button> |
| | | <el-button>设置</el-button> |
| | | <el-button @click="openDialog">设置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | |
| | | <el-form label-position="left"> |
| | | <el-form-item> |
| | | <el-button>写入</el-button> |
| | | <el-button>设置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </el-card> |
| | | </div> |
| | | </el-main> |
| | | <setting ref="settingDialogRef" :title="title" v-model:listStationsData="listStationsData" v-model:stationValue="stationValue" /> |
| | | </el-container> |
| | | </template> |
| | | |
| | |
| | | import { getDictDataItem as di, getDictDataList as dl } from '/@/utils/dict-utils'; |
| | | import { listWcsPlc } from '/@/api/wcs/wcsPlc'; |
| | | |
| | | import setting from '/@/views/device/deviceMonitor/component/setting.vue' |
| | | |
| | | const stations = ref<any>([]); |
| | | const listStationsData = ref<any>([]); |
| | | const listStackingMachineData = ref<any>([]); |
| | | const lineOptions = ref<any>([]); |
| | | const lineValue = ref(1); |
| | | const title = ref<string>(''); |
| | | const stationValue = ref<any>({ |
| | | taskNo: '', |
| | | taskType: '', |
| | |
| | | wcs: '', |
| | | status: false |
| | | }); |
| | | |
| | | const settingDialogRef = ref(); |
| | | // 打开打印页面 |
| | | const openDialog = async () => { |
| | | settingDialogRef.value.openDialog(stationValue); |
| | | } |
| | | // 查询操作 |
| | | const handleQuery = async () => { |
| | | var listplc = await listWcsPlc({ type: 1 }); |
| | |
| | | listStationsData.value = stations.value[lineValue.value]; |
| | | stationValue.value = listStationsData.value[0]; |
| | | } |
| | | title.value = listStationsData.value[0].text; |
| | | }; |
| | | |
| | | handleQuery(); |
| | | |
| | | const handleLineChange = (field: string, value: number) => { |
| | | listStationsData.value = stations.value[value]; |
| | | title.value = lineOptions.value.filter(s => s.id == value)[0].text; |
| | | if (listStationsData.value.length > 0) |
| | | stationValue.value = listStationsData.value[0]; |
| | | }; |
| | |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .el-button { |
| | | background-color: #fff; |
| | | border-color: #fff; |
| | | color: #000000; |
| | | } |
| | | |
| | | .linefix { |
| | | border-bottom: 1px solid rgb(197, 195, 195); |
| | | display: flex; |