213 lines
9.8 KiB
C#
Raw Normal View History

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using VOL.Business.IServices.SunshineRun;
using VOL.Core.EFDbContext;
using VOL.Core.Extensions.AutofacManager;
using VOL.Core.ManageUser;
using VOL.Entity.DomainModels;
using VOL.Model;
using VOL.Model.SunshineRun;
namespace VOL.Business.Services.SunshineRun
{
public class SunshineRunService : ISunshineRunService, IDependency
{
private readonly VOLContext _dbContext;
public SunshineRunService(VOLContext dbContext)
{
_dbContext = dbContext;
}
public async Task<PageDataDto<SunshineRunRecordModel>> GetPageList(SunshineRunPageParam param)
{
param ??= new SunshineRunPageParam();
ValidateDateRange(param);
var schoolId = await GetSchoolId();
var total = await GetCount(param, schoolId);
var records = await GetRecords(param, schoolId, param.PageIndex, param.PageSize);
return new PageDataDto<SunshineRunRecordModel>
{
Total = total,
TotalPages = (int)Math.Ceiling(total / (double)param.PageSize),
PageIndex = param.PageIndex,
PageSize = param.PageSize,
Datas = records
};
}
public async Task<List<SunshineRunRecordModel>> GetExportList(SunshineRunFilterParam param)
{
param ??= new SunshineRunFilterParam();
ValidateDateRange(param);
return await GetRecords(param, await GetSchoolId(), null, null);
}
private static void ValidateDateRange(SunshineRunFilterParam param)
{
if (param.StartDate.HasValue && param.EndDate.HasValue &&
param.StartDate.Value.Date > param.EndDate.Value.Date)
throw new ArgumentException("结束日期不能早于开始日期");
}
private async Task<string> GetSchoolId()
{
if (UserContext.Current.IsSuperAdmin)
return null;
var schoolId = await _dbContext.Set<S_School>().AsNoTracking()
.Where(x => x.SchoolCode == UserContext.Current.TenantId)
.Select(x => (int?)x.Id)
.FirstOrDefaultAsync();
return schoolId?.ToString(CultureInfo.InvariantCulture) ?? string.Empty;
}
private static string BuildWhere(SunshineRunFilterParam param, string schoolId)
{
var conditions = new List<string> { "1 = 1" };
if (schoolId != null)
conditions.Add("r.OrgId = @OrgId");
if (!string.IsNullOrWhiteSpace(param.StudentName))
conditions.Add("r.StudentName LIKE @StudentName");
if (!string.IsNullOrWhiteSpace(param.ClassName))
conditions.Add("(r.ClassName LIKE @ClassName OR CONCAT(r.GradeName, r.ClassName) LIKE @ClassName)");
if (param.GradeId.HasValue)
conditions.Add("r.GradeId = @GradeId");
if (param.ClassId.HasValue)
conditions.Add("r.ClassId = @ClassId");
// CreateTime is stored as an ISO-formatted string in XW_SunshineRunTrain.
if (param.StartDate.HasValue)
conditions.Add("r.CreateTime >= @StartDate");
if (param.EndDate.HasValue)
conditions.Add("r.CreateTime < @EndDateExclusive");
return string.Join(" AND ", conditions);
}
private static void AddParameter(DbCommand command, string name, object value)
{
var parameter = command.CreateParameter();
parameter.ParameterName = name;
parameter.Value = value ?? DBNull.Value;
command.Parameters.Add(parameter);
}
private static void AddFilters(DbCommand command, SunshineRunFilterParam param, string schoolId)
{
if (schoolId != null)
AddParameter(command, "@OrgId", schoolId);
if (!string.IsNullOrWhiteSpace(param.StudentName))
AddParameter(command, "@StudentName", "%" + param.StudentName.Trim() + "%");
if (!string.IsNullOrWhiteSpace(param.ClassName))
AddParameter(command, "@ClassName", "%" + param.ClassName.Trim() + "%");
if (param.GradeId.HasValue)
AddParameter(command, "@GradeId", param.GradeId.Value.ToString(CultureInfo.InvariantCulture));
if (param.ClassId.HasValue)
AddParameter(command, "@ClassId", param.ClassId.Value.ToString(CultureInfo.InvariantCulture));
if (param.StartDate.HasValue)
AddParameter(command, "@StartDate",
param.StartDate.Value.Date.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
if (param.EndDate.HasValue)
AddParameter(command, "@EndDateExclusive",
param.EndDate.Value.Date.AddDays(1).ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
}
private async Task<int> GetCount(SunshineRunFilterParam param, string schoolId)
{
var connection = _dbContext.Database.GetDbConnection();
await connection.OpenAsync();
try
{
await using var command = connection.CreateCommand();
command.CommandText = "SELECT COUNT(*) FROM XW_SunshineRunTrain r WHERE " + BuildWhere(param, schoolId);
AddFilters(command, param, schoolId);
return Convert.ToInt32(await command.ExecuteScalarAsync(), CultureInfo.InvariantCulture);
}
finally
{
await connection.CloseAsync();
}
}
private async Task<List<SunshineRunRecordModel>> GetRecords(
SunshineRunFilterParam param, string schoolId, int? pageIndex, int? pageSize)
{
var connection = _dbContext.Database.GetDbConnection();
await connection.OpenAsync();
try
{
await using var command = connection.CreateCommand();
command.CommandText = @"SELECT r.StudentName, r.Sex, r.GradeName, r.ClassName,
r.EffectiveDistance, r.InvalidDistance, r.Times, r.InvalidTimes, r.CreateTime
FROM XW_SunshineRunTrain r WHERE " + BuildWhere(param, schoolId) +
" ORDER BY r.CreateTime DESC, r.Id DESC" +
(pageIndex.HasValue ? " OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY" : "");
AddFilters(command, param, schoolId);
if (pageIndex.HasValue)
{
AddParameter(command, "@Offset", (pageIndex.Value - 1) * pageSize.Value);
AddParameter(command, "@PageSize", pageSize.Value);
}
var rows = new List<SunshineRunRecordModel>();
await using var reader = await command.ExecuteReaderAsync();
var index = pageIndex.HasValue ? (pageIndex.Value - 1) * pageSize.Value : 0;
while (await reader.ReadAsync())
{
var effectiveDistance = GetInt(reader, 4);
var invalidDistance = GetInt(reader, 5);
var seconds = GetInt(reader, 6);
var invalidSeconds = GetInt(reader, 7);
var start = reader.IsDBNull(8) ? null : reader.GetString(8);
var parsedStart = DateTime.TryParse(start, CultureInfo.InvariantCulture,
DateTimeStyles.None, out var startTime);
rows.Add(new SunshineRunRecordModel
{
Index = ++index,
StudentName = GetString(reader, 0),
SexName = GetInt(reader, 1) switch { 1 => "男", 2 => "女", _ => "-" },
ClassName = string.Join(" ", new[] { GetString(reader, 2), GetString(reader, 3) }
.Where(x => !string.IsNullOrWhiteSpace(x))),
EffectiveDistance = FormatDistance(effectiveDistance),
EffectiveTime = FormatTime(seconds.HasValue
? Math.Max(0, seconds.Value - (invalidSeconds ?? 0)) : null),
TotalDistance = FormatDistance(effectiveDistance.HasValue || invalidDistance.HasValue
? (effectiveDistance ?? 0) + (invalidDistance ?? 0) : null),
TotalTime = FormatTime(seconds),
StartTime = parsedStart ? startTime.ToString("yyyy-MM-dd HH:mm:ss") : start ?? "-",
EndTime = parsedStart && seconds.HasValue
? startTime.AddSeconds(seconds.Value).ToString("yyyy-MM-dd HH:mm:ss") : "-"
});
}
return rows;
}
finally
{
await connection.CloseAsync();
}
}
private static string GetString(DbDataReader reader, int ordinal)
=> reader.IsDBNull(ordinal) ? string.Empty : reader.GetString(ordinal);
private static int? GetInt(DbDataReader reader, int ordinal)
=> reader.IsDBNull(ordinal) ? null : Convert.ToInt32(reader.GetValue(ordinal), CultureInfo.InvariantCulture);
private static string FormatDistance(int? meters)
=> meters.HasValue ? (meters.Value / 1000m).ToString("0.##", CultureInfo.InvariantCulture) + "公里" : "-";
private static string FormatTime(int? seconds)
{
if (!seconds.HasValue)
return "-";
var value = Math.Max(0, seconds.Value);
var minutes = value / 60;
return minutes > 0 ? minutes + "分" + value % 60 + "秒" : value + "秒";
}
}
}