using NPOI.SS.Formula.Functions;
using NPOI.Util;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TeamAAS_VP.Interfaces;
using TeamAAS_VP.Models;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
namespace TeamAAS_VP.Data
{
///
/// 系统数据库服务,基于 提供对应用数据的访问。
/// 包含用户增删改查、用户身份验证以及生产记录的写入与统计功能。
///
public class SystemDatabaseService : ISystemDatabaseService
{
private readonly ISqlSugarClient _db;
private User CurrentUser { get; set; }
///
/// 使用指定的 SqlSugar 客户端构造数据库服务实例。
///
/// 已配置的 实例。
public SystemDatabaseService(ISqlSugarClient db)
{
_db = db;
//GenerateTestDataAsync();
}
#region 用户
// User CRUD
///
/// 添加新用户到数据库。
/// 对于 SqlSugar,User.Id 为数据库自增值,因此在此方法中不应设定 Id。
///
/// 要添加的用户对象,不能为空。
/// 返回传入的用户对象(Id 由数据库生成后会回写到该对象)。
/// 当 为 null 时抛出。
public async Task AddUserAsync(User user)
{
if (user == null) throw new ArgumentNullException(nameof(user));
// for SqlSugar User.Id is int identity, so do not set it here
await _db.Insertable(user).ExecuteCommandAsync();
return user;
}
///
/// 根据用户 Id 删除用户。
///
/// 要删除的用户 Id。
/// 如果删除了至少一条记录则返回 true,否则返回 false。
public async Task DeleteUserAsync(int userId)
{
var r = await _db.Deleteable().In(userId).ExecuteCommandAsync();
return r > 0;
}
///
/// 获取所有用户。
///
/// 用户列表的异步枚举。
public async Task> GetAllUsersAsync()
{
return await _db.Queryable().ToListAsync();
}
///
/// 根据用户 Id 查询单个用户。
///
/// 用户 Id。
/// 匹配的用户,如果未找到则返回 null(取决于 SqlSugar 的行为)。
public async Task GetUserByIdAsync(int userId)
{
return await _db.Queryable().InSingleAsync(userId);
}
///
/// 更新用户信息并返回更新后的对象。
///
/// 要更新的用户对象,不能为空。
/// 返回传入的用户对象。
/// 当 为 null 时抛出。
public async Task UpdateUserAsync(User user)
{
if (user == null) throw new ArgumentNullException(nameof(user));
var r = await _db.Updateable(user).ExecuteCommandAsync();
return user;
}
// User authentication
///
/// 验证用户名和密码并返回匹配的用户。
/// 注意:当前实现直接以明文密码比较,请根据需要在调用侧或更高层添加哈希/盐策略。
///
/// 用户名,不能为空或空字符串。
/// 密码,不能为空或空字符串。
/// 匹配的用户对象,如果未找到则可能抛出或返回 null(取决于 SqlSugar 的 FirstAsync 行为)。
/// 当 或 为空时抛出。
public async Task AuthenticateUserAsync(string username, string password)
{
if (string.IsNullOrEmpty(username)) throw new ArgumentException("username is required", nameof(username));
if (string.IsNullOrEmpty(password)) throw new ArgumentException("password is required", nameof(password));
return await _db.Queryable().Where(u => u.UserName == username && u.UserPassword == password).FirstAsync();
}
// User login / current user helpers
///
/// 将指定用户设为当前用户(写入一条成功的登录记录)。
///
/// 要设为当前用户的用户 Id。
public async Task SetCurrentUserAsync(int userId)
{
// 验证用户存在
var user = await GetUserByIdAsync(userId);
if (user == null)
{
throw new ArgumentException($"User with id {userId} not found", nameof(userId));
}
CurrentUser = user;
// 记录一条成功的登录记录
var rec = new UserLoginRecord
{
UserId = userId,
Success = true,
Time = DateTime.Now,
Message = "Set as current user"
};
await RecordUserLoginAsync(rec);
}
///
/// 将指定用户设为当前用户(会写入一条登录记录,标记为成功)
///
///
///
public async Task SetCurrentUserAsync(User user)
{
CurrentUser = user;
// 记录一条成功的登录记录
var rec = new UserLoginRecord
{
UserId = user.Id,
Success = true,
Time = DateTime.Now,
Message = user.UserName
};
await RecordUserLoginAsync(rec);
}
///
/// 获取最近一次成功登录的用户(视为当前用户)。
///
/// 若存在成功登录记录则返回对应用户,否则返回 null。
public Task GetCurrentUserAsync()
{
return Task.FromResult(GetCurrentUser());
}
///
/// 获取当前用户
///
///
public User GetCurrentUser()
{
//var recs = _db.Queryable()
// .Where(r => r.Success == true)
// .OrderBy(r => r.Time, OrderByType.Desc)
// .Take(1)
// .ToList();
//var rec = recs.FirstOrDefault();
////如果没有登录记录则返回一个默认的用户,即第一个用户
//if (rec == null) return _db.Queryable().First();
//return _db.Queryable().InSingle(rec.UserId);
if (CurrentUser == null)
{
CurrentUser = _db.Queryable().ToList().FirstOrDefault();
}
return CurrentUser;
}
///
/// 记录一条用户登录记录(成功或失败)。
///
/// 登录记录对象,不能为空。
public async Task RecordUserLoginAsync(UserLoginRecord record)
{
if (record == null) throw new ArgumentNullException(nameof(record));
if (record.Time == default(DateTime)) record.Time = DateTime.Now;
await _db.Insertable(record).ExecuteCommandAsync();
}
///
/// 获取指定用户最近的一条登录记录(无论是否成功)。
///
/// 用户 Id。
/// 最近的一条登录记录或 null。
public async Task GetLastUserLoginRecordAsync(int userId)
{
var recs = await _db.Queryable()
.Where(r => r.UserId == userId)
.OrderBy(r => r.Time, OrderByType.Desc)
.Take(1)
.ToListAsync();
return recs.FirstOrDefault();
}
///
/// 将指定用户名标记为“记住”,并取消其他用户的记住标志。
///
/// 要记住的用户名。
public async Task SetRememberUserAsync(string username)
{
if (string.IsNullOrEmpty(username)) throw new ArgumentException("username is required", nameof(username));
// 使用事务先清除所有记住标志,再为指定用户设置记住
try
{
_db.Ado.BeginTran();
// 清除所有
await _db.Updateable().SetColumns(u => new User { IsRemember = false }).Where("1=1").ExecuteCommandAsync();
// 设置指定用户为记住
await _db.Updateable().SetColumns(u => new User { IsRemember = true }).Where(u => u.UserName == username).ExecuteCommandAsync();
_db.Ado.CommitTran();
}
catch
{
try { _db.Ado.RollbackTran(); } catch { }
throw;
}
}
///
/// 清除所有用户的记住标志。
///
public async Task ClearRememberUserAsync()
{
await _db.Updateable().SetColumns(u => new User { IsRemember = false }).ExecuteCommandAsync();
}
///
/// 获取当前被标记为记住的用户(如果存在)。
///
/// 被记住的用户或 null。
public async Task GetRememberedUserAsync()
{
return await _db.Queryable().Where(u => u.IsRemember == true).FirstAsync();
}
#endregion
#region 生产记录
// Production records
///
/// 记录一次生产事件。如果 为
/// 则会自动生成新的 Guid。
///
/// 生产记录对象,不能为空。
/// 异步任务。
/// 当 为 null 时抛出。
public async Task RecordProductionAsync(ProductionRecord record)
{
if (record == null) throw new ArgumentNullException(nameof(record));
// 如果未指定产生该记录的用户名,尝试使用当前登录用户
if (string.IsNullOrEmpty(record.UserName))
{
try
{
var current = await GetCurrentUserAsync();
if (current != null)
{
record.UserName = current.UserName;
}
}
catch
{
// 忽略获取当前用户时的错误,继续保存记录(保守策略)
}
}
record.Id = record.Id == Guid.Empty ? Guid.NewGuid() : record.Id;
await _db.Insertable(record).ExecuteCommandAsync();
}
///
/// 重置生产记录。若未传入
/// 则清空所有生产记录;否则仅删除指定产品名的记录。
///
/// 可选的产品名过滤。
/// 异步任务。
public async Task ResetProductionAsync(string productName = null)
{
if (string.IsNullOrEmpty(productName))
{
await _db.Deleteable().Where("1=1").ExecuteCommandAsync();
}
else
{
await _db.Deleteable().Where(r => r.ProductName == productName).ExecuteCommandAsync();
}
}
///
/// 获取指定产品(和可选类别)在数据库中累计的产量总和(仅统计 Quantity > 0 的记录)。
///
/// 产品名,不能为空或空字符串。
/// 可选的类别集合,用于过滤。
/// 指定条件下的产量总和(整数)。
/// 当 为空时抛出。
public async Task GetTotalProductionAsync(string productName, IEnumerable categories = null)
{
if (string.IsNullOrEmpty(productName)) throw new ArgumentException("productName is required", nameof(productName));
var q = _db.Queryable().Where(r => r.ProductName == productName && r.Quantity > 0);
if (categories != null && categories.Any())
{
q = q.Where(r => categories.Contains(r.Category));
}
var sum = await q.SumAsync(r => r.Quantity);
return sum;
}
///
/// 获取生产统计结果,按指定时间范围、产品名和可选类别筛选,
/// 并根据 (hour/day/week/month/total)进行分组聚合。
///
/// 生产统计查询对象,不能为空,必须包含 ProductName/Start/End 等。
/// 按指定分组粒度返回的统计结果集合。
/// 当 为 null 时抛出。
public async Task> GetProductionStatsAsync(ProductionStatQuery query)
{
if (query == null) throw new ArgumentNullException(nameof(query));
if (string.IsNullOrEmpty(query.ProductName)) throw new ArgumentException("ProductName is required in query", nameof(query));
var q = _db.Queryable().Where(r => r.ProductName == query.ProductName && r.Timestamp >= query.Start && r.Timestamp < query.End);
if (query.Categories != null && query.Categories.Any())
{
q = q.Where(r => query.Categories.Contains(r.Category));
}
var list = await q.ToListAsync();
var results = new List();
switch ((query.GroupBy ?? "total").ToLower())
{
case "hour":
// group by hour
var hours = list.GroupBy(r => new DateTime(r.Timestamp.Year, r.Timestamp.Month, r.Timestamp.Day, r.Timestamp.Hour, 0, 0))
.OrderBy(g => g.Key);
foreach (var g in hours)
{
results.Add(new ProductionStatResult { PeriodStart = g.Key, PeriodEnd = g.Key.AddHours(1), Quantity = g.Sum(x => x.Quantity), ProductName = query.ProductName });
}
break;
case "day":
var days = list.GroupBy(r => r.Timestamp.Date).OrderBy(g => g.Key);
foreach (var g in days)
{
results.Add(new ProductionStatResult { PeriodStart = g.Key, PeriodEnd = g.Key.AddDays(1), Quantity = g.Sum(x => x.Quantity), ProductName = query.ProductName });
}
break;
case "week":
// ISO week grouping by week start (Monday)
var weeks = list.GroupBy(r => FirstDayOfWeek(r.Timestamp)).OrderBy(g => g.Key);
foreach (var g in weeks)
{
results.Add(new ProductionStatResult { PeriodStart = g.Key, PeriodEnd = g.Key.AddDays(7), Quantity = g.Sum(x => x.Quantity), ProductName = query.ProductName });
}
break;
case "month":
var months = list.GroupBy(r => new DateTime(r.Timestamp.Year, r.Timestamp.Month, 1)).OrderBy(g => g.Key);
foreach (var g in months)
{
results.Add(new ProductionStatResult { PeriodStart = g.Key, PeriodEnd = g.Key.AddMonths(1), Quantity = g.Sum(x => x.Quantity), ProductName = query.ProductName });
}
break;
default:
results.Add(new ProductionStatResult { PeriodStart = query.Start, PeriodEnd = query.End, Quantity = list.Sum(x => x.Quantity), ProductName = query.ProductName });
break;
}
return results;
}
///
/// 获取所有已知分类相加起来的今天的产能
///
///
///
public async Task GetTodayProductionAsync(string productName)
{
//今天的起始时间
var todayStart = DateTime.Now.Date;
//今天的结束时间
var todayEnd = DateTime.Now.Date;
todayEnd = todayEnd.AddDays(1);
//按照产品名称和时间范围查询生产记录的总数
var total = await _db.Queryable()
.Where(r => r.ProductName == productName && r.Timestamp >= todayStart && r.Timestamp < todayEnd)
.SumAsync(r => r.Quantity);
return total;
}
///
/// 获取所有已知分类相加起来的当前时间往前的一个小时的产能
///
///
///
public async Task GetLastHourProductionAsync(string productName)
{
var lastHourStart = DateTime.Now.AddHours(-1);
var lastHourEnd = DateTime.Now;
//按照产品名称和时间范围查询生产记录的总数
var total = await _db.Queryable()
.Where(r => r.ProductName == productName && r.Timestamp >= lastHourStart && r.Timestamp < lastHourEnd)
.SumAsync(r => r.Quantity);
return total;
}
///
/// 获取今天ng的数量
///
///
///
public async Task GetNGProductionAsync(string productName)
{
//今天的起始时间
var todayStart = DateTime.Now.Date;
//今天的结束时间
var todayEnd = DateTime.Now.Date;
todayEnd = todayEnd.AddDays(1);
//按照产品名称和时间范围查询生产记录的总数
var total = await _db.Queryable()
.Where(r => r.ProductName == productName && r.Timestamp >= todayStart && r.Timestamp < todayEnd && r.Category == "NG")
.SumAsync(r => r.Quantity);
return total;
}
///
/// 获取当前月的产能
///
///
///
public Task GetCurrentMonthProductionAsync(string productName)
{
var now = DateTime.Now;
var monthStart = new DateTime(now.Year, now.Month, 1);
var monthEnd = monthStart.AddMonths(1);
//按照产品名称和时间范围查询生产记录的总数
return _db.Queryable()
.Where(r => r.ProductName == productName && r.Timestamp >= monthStart && r.Timestamp < monthEnd)
.SumAsync(r => r.Quantity);
}
///
/// 获取当前周的产能
///
///
///
public Task GetCurrentWeekProductionAsync(string productName)
{
var now = DateTime.Now;
var weekStart = FirstDayOfWeek(now);
var weekEnd = weekStart.AddDays(7);
//按照产品名称和时间范围查询生产记录的总数
return _db.Queryable()
.Where(r => r.ProductName == productName && r.Timestamp >= weekStart && r.Timestamp < weekEnd)
.SumAsync(r => r.Quantity);
}
///
/// 计算给定日期所属周的第一天(以星期一为一周的第一天)。
/// 返回结果为日期的 Date 部分(时间为 00:00:00)。
///
/// 输入日期。
/// 该日期对应周的周一日期(Date 部分)。
private DateTime FirstDayOfWeek(DateTime dt)
{
var diff = (7 + (dt.DayOfWeek - DayOfWeek.Monday)) % 7;
return dt.Date.AddDays(-1 * diff);
}
///
/// 获取指定产品名称的总产能
///
///
///
public Task GetOverallProductionAsync(string productName)
{
return _db.Queryable()
.Where(r => r.ProductName == productName)
.SumAsync(r => r.Quantity);
}
///
/// 获取指定产品的所有已知分类。
///
/// 要查询分类的产品名称。
///
/// 一个字符串集合,包含该产品的所有分类名称;如果没有分类,返回空集合或 null(建议返回空集合)。
///
public async Task> GetProductCategoriesAsync(string productName)
{
var categories = await _db.Queryable()
.Where(r => r.ProductName == productName)
.Select(r => r.Category)
.Distinct()
.ToListAsync();
return categories;
}
///
/// 获取指定产品名称的所有记录按照分类的产能统计
///
///
///
public async Task> GetProductionByCategoriesAsync(string productName)
{
var list = await _db.Queryable()
.Where(r => r.ProductName == productName)
.ToListAsync();
var dict = list.GroupBy(r => r.Category)
.ToDictionary(g => g.Key, g => g.Sum(r => r.Quantity));
return dict;
}
///
/// 获取指定产品名称的一个月内按照每天统计对应的类别和数量
///
///
///
public async Task>> GetMonthlyProductionByDayAndCategoryAsync(string productName)
{
var now = DateTime.Now;
var monthStart = new DateTime(now.Year, now.Month, 1);
var monthEnd = monthStart.AddMonths(1);
var list = await _db.Queryable()
.Where(r => r.ProductName == productName && (r.Timestamp >= monthStart && r.Timestamp < monthEnd))
.ToListAsync();
var dict = new Dictionary>();
var days = list.GroupBy(r => r.Timestamp.Date).OrderBy(g => g.Key);
foreach (var dayGroup in days)
{
var categoryDict = dayGroup.GroupBy(r => r.Category)
.ToDictionary(g => g.Key, g => g.Sum(r => r.Quantity));
dict[dayGroup.Key] = categoryDict;
}
return dict;
}
///
/// 获取指定产品名称的一个星期内按照每天统计对应的类别和数量
///
///
///
public async Task>> GetWeeklyProductionByDayAndCategoryAsync(string productName)
{
var now = DateTime.Now;
var weekStart = FirstDayOfWeek(now);
var weekEnd = weekStart.AddDays(7);
var list = await _db.Queryable()
.Where(r => r.ProductName == productName && r.Timestamp >= weekStart && r.Timestamp < weekEnd)
.ToListAsync();
var dict = new Dictionary>();
var days = list.GroupBy(r => r.Timestamp.DayOfWeek).OrderBy(g => g.Key);
foreach (var dayGroup in days)
{
var categoryDict = dayGroup.GroupBy(r => r.Category)
.ToDictionary(g => g.Key, g => g.Sum(r => r.Quantity));
dict[(int)dayGroup.Key] = categoryDict;
}
return dict;
}
///
/// 获取指定产品名称的当天内按照每小时统计对应的类别和数量
///
///
///
public async Task>> GetDailyProductionByHourAndCategoryAsync(string productName)
{
var now = DateTime.Now;
var dayStart = now.Date;
var dayEnd = dayStart.AddDays(1);
var list = await _db.Queryable()
.Where(r => r.ProductName == productName && r.Timestamp >= dayStart && r.Timestamp < dayEnd)
.ToListAsync();
var dict = new Dictionary>();
var hours = list.GroupBy(r => r.Timestamp.Hour).OrderBy(g => g.Key);
foreach (var hourGroup in hours)
{
var categoryDict = hourGroup.GroupBy(r => r.Category)
.ToDictionary(g => g.Key, g => g.Sum(r => r.Quantity));
dict[hourGroup.Key] = categoryDict;
}
return dict;
}
///
/// 分页查询生产记录
///
public async Task<(IEnumerable Items, int TotalCount)> QueryProductionRecordsPagedAsync(DateTime start, DateTime end, int pageIndex, int pageSize, string productName = null, string category = null)
{
if (pageIndex < 1) pageIndex = 1;
if (pageSize < 1) pageSize = 20;
var q = _db.Queryable().Where(r => r.Timestamp >= start && r.Timestamp < end);
if (!string.IsNullOrEmpty(productName)) q = q.Where(r => r.ProductName == productName);
if (!string.IsNullOrEmpty(category)) q = q.Where(r => r.Category == category);
var total = await q.CountAsync();
var list = await q.OrderBy(r => r.Timestamp, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
return (list, total);
}
#endregion
#region 报警记录
// Alarm Records
///
/// 记录一条报警记录。
///
/// 报警记录对象,不能为空。
public async Task RecordAlarmAsync(AlarmRecord alarm)
{
if (alarm == null) throw new ArgumentNullException(nameof(alarm));
if (alarm.Time == default(DateTime)) alarm.Time = DateTime.Now;
await _db.Insertable(alarm).ExecuteCommandAsync();
}
///
/// 按时间范围和可选条件查询报警记录。
///
/// 起始时间(含)。
/// 结束时间(不含)。
/// 可选的报警编号过滤。
/// 可选的报警来源过滤。
/// 满足条件的报警记录集合。
public async Task> QueryAlarmsAsync(DateTime start, DateTime end, string code = null, string source = null)
{
var q = _db.Queryable().Where(a => a.Time >= start && a.Time < end);
if (!string.IsNullOrEmpty(code)) q = q.Where(a => a.Code == code);
if (!string.IsNullOrEmpty(source)) q = q.Where(a => a.Source == source);
return await q.OrderBy(a => a.Time, OrderByType.Desc).ToListAsync();
}
#endregion
#region 锁付结果记录
// Lock result methods
///
/// 记录单次锁付结果(WaveDatas 不写入数据库)
///
///
public async Task RecordLockResultAsync(LockResult result)
{
try
{
if (result == null) throw new ArgumentNullException(nameof(result));
if (result.Timestamp == default(DateTime)) result.Timestamp = DateTime.Now;
await _db.Insertable(result).ExecuteCommandAsync();
}
catch (Exception)
{
}
}
///
/// 分页查询锁付结果
///
public async Task<(IEnumerable Items, int TotalCount)> QueryLockResultsAsync(DateTime start, DateTime end, int pageIndex, int pageSize, string productNumber = null, string productName = null, int? screwNumber = null, bool? lockPassed = null)
{
if (pageIndex < 1) pageIndex = 1;
if (pageSize < 1) pageSize = 20;
var q = _db.Queryable().Where(r => r.Timestamp >= start && r.Timestamp < end);
if (!string.IsNullOrEmpty(productNumber)) q = q.Where(r => r.ProductNumber == productNumber);
if (screwNumber.HasValue) q = q.Where(r => r.Number == screwNumber.Value);
if (lockPassed.HasValue) q = q.Where(r => r.LockPassed == lockPassed.Value);
if (!string.IsNullOrEmpty(productName)) q = q.Where(r => r.ProductName == productName);
var total = await q.CountAsync();
var list = await q.OrderBy(r => r.Timestamp, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
return (list, total);
}
///
/// 查询所有符合条件的锁付结果(不分页)。
///
public async Task> QueryAllLockResultsAsync(DateTime start, DateTime end, string productNumber = null, string productName = null, int? screwNumber = null, bool? lockPassed = null)
{
var q = _db.Queryable().Where(r => r.Timestamp >= start && r.Timestamp < end);
if (!string.IsNullOrEmpty(productNumber)) q = q.Where(r => r.ProductNumber == productNumber);
if (screwNumber.HasValue) q = q.Where(r => r.Number == screwNumber.Value);
if (lockPassed.HasValue) q = q.Where(r => r.LockPassed == lockPassed.Value);
if (!string.IsNullOrEmpty(productName)) q = q.Where(r => r.ProductName == productName);
var list = await q.OrderBy(r => r.Timestamp, OrderByType.Desc).ToListAsync();
return list;
}
#endregion
#region 螺丝供料器批次记录
///
/// 记录一次螺丝供料器批次更换记录
///
///
///
public async Task RecordScrewFeederBatchAsync(ScrewFeederBatchRecord record)
{
if (record == null) throw new ArgumentNullException(nameof(record));
if (record.ChangeTime == default(DateTime)) record.ChangeTime = DateTime.Now;
record.Id = record.Id == Guid.Empty ? Guid.NewGuid() : record.Id;
await _db.Insertable(record).ExecuteCommandAsync();
}
///
/// 查询螺丝供料器批次记录。
/// 可按时间段、批次号精确匹配及供料器编号过滤。所有参数均为可选,传入 null 表示不作为过滤条件。
///
/// 可选:起始时间(包含)
/// 可选:结束时间(包含)
/// 可选:批次号(精确匹配)
/// 可选:供料器编号
/// 满足条件的记录集合(按 ChangeTime 降序)。
public async Task> QueryScrewFeederBatchRecordsAsync(DateTime? start = null, DateTime? end = null, string batchNumber = null, int? feederNumber = null)
{
var q = _db.Queryable();
if (start.HasValue)
q = q.Where(r => r.ChangeTime >= start.Value);
if (end.HasValue)
q = q.Where(r => r.ChangeTime <= end.Value);
if (!string.IsNullOrEmpty(batchNumber))
q = q.Where(r => r.BatchNumber == batchNumber);
if (feederNumber.HasValue)
q = q.Where(r => r.FeederNumber == feederNumber.Value);
var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToListAsync();
return list;
}
///
/// 分页查询螺丝供料器批次记录
///
public async Task<(IEnumerable Items, int TotalCount)> QueryScrewFeederBatchRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string batchNumber = null, int? feederNumber = null, int pageIndex = 1, int pageSize = 20)
{
if (pageIndex < 1) pageIndex = 1;
if (pageSize < 1) pageSize = 20;
var q = _db.Queryable();
if (start.HasValue) q = q.Where(r => r.ChangeTime >= start.Value);
if (end.HasValue) q = q.Where(r => r.ChangeTime <= end.Value);
if (!string.IsNullOrEmpty(batchNumber)) q = q.Where(r => r.BatchNumber == batchNumber);
if (feederNumber.HasValue) q = q.Where(r => r.FeederNumber == feederNumber.Value);
var total = await q.CountAsync();
var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
return (list, total);
}
///
/// 获取指定供料器编号的最新一条批次更换记录
///
///
///
public async Task GetLatestScrewFeederBatchRecordAsync(int feederNumber)
{
var recs = await _db.Queryable()
.Where(r => r.FeederNumber == feederNumber)
.OrderBy(r => r.ChangeTime, OrderByType.Desc)
.Take(1)
.ToListAsync();
return recs.FirstOrDefault();
}
#endregion
#region 拍照记录
///
/// 记录产品拍照结果
///
///
///
///
public async Task RecordPhotoCaptureAsync(PhotoCaptureRecord record)
{
if (record == null) throw new ArgumentNullException(nameof(record));
if (record.CaptureTime == default(DateTime)) record.CaptureTime = DateTime.Now;
record.Id = record.Id == Guid.Empty ? Guid.NewGuid() : record.Id;
await _db.Insertable(record).ExecuteCommandAsync();
}
///
/// 查询拍照记录,支持按配方名、产品SN和时间段过滤,参数均为可选。
///
///
///
///
///
///
///
public async Task> QueryPhotoCapturesAsync(string recipeName = null, string cameraName = null, string productSN = null, DateTime? start = null, DateTime? end = null)
{
var q = _db.Queryable();
if (!string.IsNullOrEmpty(recipeName)) q = q.Where(r => r.RecipeName == recipeName);
if (!string.IsNullOrEmpty(productSN)) q = q.Where(r => r.ProductSN == productSN);
if (start.HasValue) q = q.Where(r => r.CaptureTime >= start.Value);
if (end.HasValue) q = q.Where(r => r.CaptureTime <= end.Value);
var list = await q.OrderBy(r => r.CaptureTime, OrderByType.Desc).ToListAsync();
return list;
}
///
/// 分页查询拍照记录
///
public async Task<(IEnumerable Items, int TotalCount)> QueryPhotoCapturesPagedAsync(string recipeName = null, string cameraName = null, string productSN = null, DateTime? start = null, DateTime? end = null, int pageIndex = 1, int pageSize = 20)
{
if (pageIndex < 1) pageIndex = 1;
if (pageSize < 1) pageSize = 20;
var q = _db.Queryable();
if (!string.IsNullOrEmpty(recipeName)) q = q.Where(r => r.RecipeName == recipeName);
if (!string.IsNullOrEmpty(cameraName)) q = q.Where(r => r.CameraName == cameraName);
if (!string.IsNullOrEmpty(productSN)) q = q.Where(r => r.ProductSN == productSN);
if (start.HasValue) q = q.Where(r => r.CaptureTime >= start.Value);
if (end.HasValue) q = q.Where(r => r.CaptureTime <= end.Value);
var total = await q.CountAsync();
var list = await q.OrderBy(r => r.CaptureTime, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
return (list, total);
}
#endregion
#region 披头更换记录
///
/// 记录披头更换
///
///
///
///
public async Task RecordHeadChangeAsync(HeadChangeRecord record)
{
if (record == null) throw new ArgumentNullException(nameof(record));
if (record.ChangeTime == default(DateTime)) record.ChangeTime = DateTime.Now;
record.Id = record.Id == Guid.Empty ? Guid.NewGuid() : record.Id;
await _db.Insertable(record).ExecuteCommandAsync();
}
///
/// 查询披头更换记录
///
///
///
///
///
public async Task> QueryHeadChangeRecordsAsync(DateTime? start = null, DateTime? end = null, string headBatchNumber = null)
{
var q = _db.Queryable();
if (start.HasValue) q = q.Where(r => r.ChangeTime >= start.Value);
if (end.HasValue) q = q.Where(r => r.ChangeTime <= end.Value);
if (!string.IsNullOrEmpty(headBatchNumber)) q = q.Where(r => r.HeadBatchNumber == headBatchNumber);
var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToListAsync();
return list;
}
///
/// 分页查询披头更换记录
///
public async Task<(IEnumerable Items, int TotalCount)> QueryHeadChangeRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string headBatchNumber = null, int pageIndex = 1, int pageSize = 20)
{
if (pageIndex < 1) pageIndex = 1;
if (pageSize < 1) pageSize = 20;
var q = _db.Queryable();
if (start.HasValue) q = q.Where(r => r.ChangeTime >= start.Value);
if (end.HasValue) q = q.Where(r => r.ChangeTime <= end.Value);
if (!string.IsNullOrEmpty(headBatchNumber)) q = q.Where(r => r.HeadBatchNumber == headBatchNumber);
var total = await q.CountAsync();
var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
return (list, total);
}
///
/// 获取最新的一条披头更换记录
///
///
public async Task GetLatestHeadChangeRecordAsync()
{
var recs = await _db.Queryable().OrderBy(r => r.ChangeTime, OrderByType.Desc).Take(1).ToListAsync();
return recs.FirstOrDefault();
}
///
/// 对最新披头的锁付次数进行递增并返回更新后的次数(原子操作)。
/// 若不存在记录则创建一条新记录并返回 1。
///
public async Task IncrementLatestHeadLockCountAsync(string operatorName = null)
{
// 使用事务保证原子性
try
{
_db.Ado.BeginTran();
// 获取最新记录(排他查询)
var latest = _db.Queryable().OrderBy(r => r.ChangeTime, OrderByType.Desc).Take(1).First();
if (latest == null)
{
var newRec = new HeadChangeRecord
{
ChangeTime = DateTime.Now,
HeadBatchNumber = string.Empty,
CurrentLockCount = 1,
OperatorName = operatorName
};
await _db.Insertable(newRec).ExecuteCommandAsync();
_db.Ado.CommitTran();
return 1;
}
latest.CurrentLockCount += 1;
if (!string.IsNullOrEmpty(operatorName)) latest.OperatorName = operatorName;
await _db.Updateable(latest).ExecuteCommandAsync();
_db.Ado.CommitTran();
return latest.CurrentLockCount;
}
catch
{
try { _db.Ado.RollbackTran(); } catch { }
throw;
}
}
#endregion
#region 吸嘴更换记录
///
/// 记录喷嘴更换记录。
///
///
///
public async Task RecordNozzleChangeAsync(NozzleChangeRecord record)
{
if (record == null) throw new ArgumentNullException(nameof(record));
if (record.ChangeTime == default(DateTime)) record.ChangeTime = DateTime.Now;
record.Id = record.Id == Guid.Empty ? Guid.NewGuid() : record.Id;
await _db.Insertable(record).ExecuteCommandAsync();
}
///
/// 查询喷嘴更换记录,可按时间段或喷嘴批号过滤(所有参数可选)。
///
///
///
///
///
public async Task> QueryNozzleChangeRecordsAsync(DateTime? start = null, DateTime? end = null, string nozzleBatchNumber = null)
{
var q = _db.Queryable();
if (start.HasValue) q = q.Where(r => r.ChangeTime >= start.Value);
if (end.HasValue) q = q.Where(r => r.ChangeTime <= end.Value);
if (!string.IsNullOrEmpty(nozzleBatchNumber)) q = q.Where(r => r.NozzleBatchNumber == nozzleBatchNumber);
var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToListAsync();
return list;
}
///
/// 获取最新的一条喷嘴更换记录(按 ChangeTime 降序)。
///
///
public async Task GetLatestNozzleChangeRecordAsync()
{
var recs = await _db.Queryable().OrderBy(r => r.ChangeTime, OrderByType.Desc).Take(1).ToListAsync();
return recs.FirstOrDefault();
}
///
/// 吸嘴的锁付次数进行递增并返回更新后的次数(如果不存在最新记录,则创建一条新的记录并返回 1)。
///
///
///
public async Task IncrementLatestNozzleLockCountAsync(string operatorName = null)
{
try
{
_db.Ado.BeginTran();
var latest = _db.Queryable().OrderBy(r => r.ChangeTime, OrderByType.Desc).Take(1).First();
if (latest == null)
{
var newRec = new NozzleChangeRecord
{
ChangeTime = DateTime.Now,
NozzleBatchNumber = string.Empty,
CurrentLockCount = 1,
OperatorName = operatorName
};
await _db.Insertable(newRec).ExecuteCommandAsync();
_db.Ado.CommitTran();
return 1;
}
latest.CurrentLockCount += 1;
if (!string.IsNullOrEmpty(operatorName)) latest.OperatorName = operatorName;
await _db.Updateable(latest).ExecuteCommandAsync();
_db.Ado.CommitTran();
return latest.CurrentLockCount;
}
catch
{
try { _db.Ado.RollbackTran(); } catch { }
throw;
}
}
///
/// 分页查询喷嘴更换记录
///
public async Task<(IEnumerable Items, int TotalCount)> QueryNozzleChangeRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string nozzleBatchNumber = null, int pageIndex = 1, int pageSize = 20)
{
if (pageIndex < 1) pageIndex = 1;
if (pageSize < 1) pageSize = 20;
var q = _db.Queryable();
if (start.HasValue) q = q.Where(r => r.ChangeTime >= start.Value);
if (end.HasValue) q = q.Where(r => r.ChangeTime <= end.Value);
if (!string.IsNullOrEmpty(nozzleBatchNumber)) q = q.Where(r => r.NozzleBatchNumber == nozzleBatchNumber);
var total = await q.CountAsync();
var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
return (list, total);
}
#endregion
#region 生成测试数据
//定义一个方法来生成一些测试的数据,测试数据库写入和查询功能
public async Task GenerateTestDataAsync()
{
//生成一些喷嘴更换记录的测试数据
for (int i = 0; i < 10; i++)
{
var record = new NozzleChangeRecord
{
ChangeTime = DateTime.Now.AddMinutes(-i * 10),
NozzleBatchNumber = $"Batch-{i}",
CurrentLockCount = i,
OperatorName = $"Operator-{i}"
};
await RecordNozzleChangeAsync(record);
}
//生成一些披头更换记录的测试数据
for (int i = 0; i < 10; i++)
{
var record = new HeadChangeRecord
{
ChangeTime = DateTime.Now.AddMinutes(-i * 15),
HeadBatchNumber = $"HeadBatch-{i}",
CurrentLockCount = i,
OperatorName = $"HeadOperator-{i}"
};
await RecordHeadChangeAsync(record);
}
//生成一些螺丝供料器批次更换记录的测试数据
for (int i = 0; i < 10; i++)
{
var record = new ScrewFeederBatchRecord
{
ChangeTime = DateTime.Now.AddMinutes(-i * 20),
BatchNumber = $"ScrewBatch-{i}",
FeederNumber = i + 1
};
await RecordScrewFeederBatchAsync(record);
}
//生成一些生产记录的测试数据
for (int i = 0; i < 50; i++)
{
var record = new ProductionRecord
{
Id = Guid.NewGuid(),
ProductName = "产品1",
Category = (i % 2 == 0) ? "OK" : "NG",
Quantity = 1,
Timestamp = DateTime.Now.AddMinutes(-i * 5),
UserName = "TestUser",
Remark = $"TotalSeconds:1.10"
};
await RecordProductionAsync(record);
}
//生成一些锁付结果的测试数据
for (int i = 0; i < 200; i++)
{
var result = new LockResult(i % 4, $"PN-{i % 5}", 10.5f, 0.3f, (i % 3 != 0))
{
ProductName = "产品1",
Timestamp = DateTime.Now.AddMinutes(-i * 3),
};
await RecordLockResultAsync(result);
}
//生成一些相机拍照记录的测试数据
for (int i = 0; i < 20; i++)
{
try
{
var record = new PhotoCaptureRecord
{
Id = Guid.NewGuid(),
RecipeName = "产品1",
CameraName = $"下相机",
ProductSN = $"SN-{i}",
IsSuccess = (i % 2 == 0),
CaptureTime = DateTime.Now.AddMinutes(-i * 7),
ImagePath = $"/images/photo_{i}.jpg"
};
await RecordPhotoCaptureAsync(record);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
#endregion
#region 抛料
///
/// 将一条抛料信息记录到数据库中
///
///
///
///
public async Task RecordThrowNumberAsync(ThrowRecord record)
{
if (record == null) throw new ArgumentNullException(nameof(record));
record.Id = record.Id == Guid.Empty ? Guid.NewGuid() : record.Id;
await _db.Insertable(record).ExecuteCommandAsync();
}
///
/// 获取抛料数量
///
///
public async Task GetThrowNumberAsync()
{
//今天的起始时间
var todayStart = DateTime.Now.Date;
//今天的结束时间
var todayEnd = DateTime.Now.Date;
todayEnd = todayEnd.AddDays(1);
//按照时间范围查询抛料的总数
var total = await _db.Queryable()
.Where(r => r.DayTime >= todayStart && r.DayTime < todayEnd)
.SumAsync(r => r.ThrowCount);
return total;
}
///
/// 重置抛料计数
///
///
public async Task ResetThrowNumberAsync()
{
//今天的起始时间
var todayStart = DateTime.Now.Date;
//今天的结束时间
var todayEnd = DateTime.Now.Date;
todayEnd = todayEnd.AddDays(1);
await _db.Deleteable().Where(r => r.DayTime >= todayStart && r.DayTime < todayEnd).ExecuteCommandAsync();
}
#endregion
#region 产品和mes的绑定,自动切换产品
///
/// 添加绑定信息
///
///
///
///
///
public async Task InsertProWithMesAsync(ProductWithMes record, ProductModel product)
{
//record.Id = product.ID;
record.ProductName = product.Name;
await _db.Insertable(record).ExecuteCommandAsync();
}
///
/// 删除绑定信息
///
///
///
///
public async Task DeleteProWithMesAsync(ProductModel product)
{
var v = await _db.Deleteable().Where(r => r.ProductName == product.Name).ExecuteCommandAsync();
return v;
}
///
/// 更新绑定信息
///
///
///
///
///
public async Task UpdateProductWithMesAsync(ProductWithMes record, ProductModel product)
{
if (record == null) throw new ArgumentNullException(nameof(record));
var v = await _db.Updateable(record).Where(r => r.ProductName == product.Name).ExecuteCommandAsync();
return v;
}
///
/// 查询绑定信息
///
///
///
public async Task QueryProductWithMesAsync(ProductModel product)
{
var total = await _db.Queryable().Where(r => r.ProductName == product.Name).FirstAsync();
return total;
}
///
/// 查询所有绑定信息
///
///
///
public async Task> QueryProductWithMesALLAsync()
{
var total = await _db.Queryable().ToListAsync();
return total;
}
///
/// 通过产品的编码和颜色查询产品的名称
///
///
///
public async Task QueryProductFromMesAsync(string code, string color)
{
var v = await _db.Queryable().Where(r => r.ProductCode == code && r.ProductColor == color).FirstAsync();
if (v == null || v.ProductName == null)
{
return "";
}
return v.ProductName;
}
#endregion
}
}