213 lines
9.8 KiB
C#
213 lines
9.8 KiB
C#
|
|
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 + "秒";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|