diff --git a/Src/Dlhis.Basic/Dlhis.Basic.csproj b/Src/Dlhis.Basic/Dlhis.Basic.csproj
index 6dc23042..1b0c0da7 100644
--- a/Src/Dlhis.Basic/Dlhis.Basic.csproj
+++ b/Src/Dlhis.Basic/Dlhis.Basic.csproj
@@ -28,4 +28,8 @@
+
+
+
+
diff --git a/Src/Dlhis.Basic/Summary/Controllers/SummariesController.cs b/Src/Dlhis.Basic/Summary/Controllers/SummariesController.cs
new file mode 100644
index 00000000..0f7f9fb0
--- /dev/null
+++ b/Src/Dlhis.Basic/Summary/Controllers/SummariesController.cs
@@ -0,0 +1,29 @@
+using Dlhis.Basic.Summary.Response;
+using Dlhis.Basic.Summary.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Dlhis.Basic.Summary.Controllers;
+
+[Authorize]
+[Route("api/[controller]")]
+[ApiController]
+public class SummariesController : ControllerBase
+{
+ private readonly ISummaryService _summaryService;
+
+ public SummariesController(ISummaryService summaryService)
+ {
+ _summaryService = summaryService;
+ }
+
+ ///
+ /// 考勤首页
+ ///
+ ///
+ [HttpGet("attendance-summary")]
+ public async Task GetKaoQingSummary()
+ {
+ return await _summaryService.GetAttendanceSummaryAsync();
+ }
+}
diff --git a/Src/Dlhis.Basic/Summary/Dto/TrendDto.cs b/Src/Dlhis.Basic/Summary/Dto/TrendDto.cs
new file mode 100644
index 00000000..2d2d046d
--- /dev/null
+++ b/Src/Dlhis.Basic/Summary/Dto/TrendDto.cs
@@ -0,0 +1,8 @@
+namespace Dlhis.Basic.Summary.Dto;
+
+public class TrendDto
+{
+ public DateTime Date { get; set; }
+
+ public int Count { get; set; }
+}
diff --git a/Src/Dlhis.Basic/Summary/Response/AttendanceDetailSummary.cs b/Src/Dlhis.Basic/Summary/Response/AttendanceDetailSummary.cs
new file mode 100644
index 00000000..f4f9c24a
--- /dev/null
+++ b/Src/Dlhis.Basic/Summary/Response/AttendanceDetailSummary.cs
@@ -0,0 +1,21 @@
+using Dlhis.Basic.Summary.Dto;
+
+namespace Dlhis.Basic.Summary.Response;
+
+public class AttendanceDetailSummary
+{
+ ///
+ /// 在职人数
+ ///
+ public int Employed { get; set; }
+
+ ///
+ /// 非在职人数
+ ///
+ public int Unemployed { get; set; }
+
+ ///
+ /// 人员趋势 7天
+ ///
+ public GainfoTrendResponse GainfoTrend { get; set; }
+}
diff --git a/Src/Dlhis.Basic/Summary/Response/AttendanceDeviceSummary.cs b/Src/Dlhis.Basic/Summary/Response/AttendanceDeviceSummary.cs
new file mode 100644
index 00000000..c0ebc007
--- /dev/null
+++ b/Src/Dlhis.Basic/Summary/Response/AttendanceDeviceSummary.cs
@@ -0,0 +1,26 @@
+using Dlhis.Basic.Summary.Dto;
+
+namespace Dlhis.Basic.Summary.Response;
+
+public class AttendanceDeviceSummary
+{
+ ///
+ /// 总数
+ ///
+ public int Total { get; set; }
+
+ ///
+ /// 在线数
+ ///
+ public int OnlineCount { get; set; }
+
+ ///
+ /// 启用数
+ ///
+ public int EnableCount { get; set; }
+
+ ///
+ /// 新增设备趋势 30天内
+ ///
+ public List Trend { get; set; }
+}
diff --git a/Src/Dlhis.Basic/Summary/Response/AttendanceSummaryResponse.cs b/Src/Dlhis.Basic/Summary/Response/AttendanceSummaryResponse.cs
new file mode 100644
index 00000000..ab930d60
--- /dev/null
+++ b/Src/Dlhis.Basic/Summary/Response/AttendanceSummaryResponse.cs
@@ -0,0 +1,9 @@
+namespace Dlhis.Basic.Summary.Response
+{
+ public class AttendanceSummaryResponse
+ {
+ public AttendanceDeviceSummary DeviceSummary { get; set; }
+
+ public AttendanceDetailSummary AttendanceDetailSummary { get; set; }
+ }
+}
diff --git a/Src/Dlhis.Basic/Summary/Response/GainfoTrendResponse.cs b/Src/Dlhis.Basic/Summary/Response/GainfoTrendResponse.cs
new file mode 100644
index 00000000..4050c983
--- /dev/null
+++ b/Src/Dlhis.Basic/Summary/Response/GainfoTrendResponse.cs
@@ -0,0 +1,10 @@
+using Dlhis.Basic.Summary.Dto;
+
+namespace Dlhis.Basic.Summary.Response
+{
+ public class GainfoTrendResponse
+ {
+ public List EmployedTrend { get; set; }
+ public List UnemployedTrend { get; set; }
+ }
+}
diff --git a/Src/Dlhis.Basic/Summary/Services/ISummaryService.cs b/Src/Dlhis.Basic/Summary/Services/ISummaryService.cs
new file mode 100644
index 00000000..775379d2
--- /dev/null
+++ b/Src/Dlhis.Basic/Summary/Services/ISummaryService.cs
@@ -0,0 +1,8 @@
+using Dlhis.Basic.Summary.Response;
+
+namespace Dlhis.Basic.Summary.Services;
+
+public interface ISummaryService : IScopeDependency
+{
+ Task GetAttendanceSummaryAsync();
+}
diff --git a/Src/Dlhis.Basic/Summary/Services/Implements/SummaryService.cs b/Src/Dlhis.Basic/Summary/Services/Implements/SummaryService.cs
new file mode 100644
index 00000000..ad4f3e1e
--- /dev/null
+++ b/Src/Dlhis.Basic/Summary/Services/Implements/SummaryService.cs
@@ -0,0 +1,106 @@
+using Dlhis.Basic.Organization.Services;
+using Dlhis.Basic.Summary.Dto;
+using Dlhis.Basic.Summary.Response;
+using Dlhis.Entity.Basic.Entity;
+using Dlhis.Entity.Basic.Enums;
+using Dlhis.Entity.Device.Entities;
+using Kurisu.SqlSugar.Services;
+
+namespace Dlhis.Basic.Summary.Services.Implements;
+
+public class SummaryService : ISummaryService
+{
+ private readonly IDbContext _dbContext;
+ private readonly IGainfoStore _gainfoStore;
+
+ public SummaryService(IDbContext dbContext, IGainfoStore gainfoStore)
+ {
+ _dbContext = dbContext;
+ _gainfoStore = gainfoStore;
+ }
+
+ public async Task GetAttendanceSummaryAsync()
+ {
+ var now = DateTime.Now;
+
+ var currentDay = DateTime.Today.AddDays(1).AddSeconds(-1);
+ var before30Day = DateTime.Today.AddDays(-29);
+ var before7Day = DateTime.Today.AddDays(-6);
+
+ var devices = await _dbContext.Queryable().ToListAsync();
+ var deviceUniqueNos = devices.Select(x => x.UniqueNo).ToList();
+
+ var deviceRegistries = await _dbContext.Queryable()
+ .LeftJoin((x, d) => x.DeviceUniqueNo == d.UniqueNo)
+ .Where(x => deviceUniqueNos.Contains(x.DeviceUniqueNo))
+ .Select((x, d) => new
+ {
+ d.HeartbeatInterval,
+ x.LastHeartbeatTime
+ })
+ .ToListAsync();
+
+ var workingGainfos = await _gainfoStore.Queryable(GainfoStatusEnumType.Working).ToListAsync();
+ var leaveGainfos = await _gainfoStore.Queryable(GainfoStatusEnumType.Leave).ToListAsync();
+
+ return new AttendanceSummaryResponse
+ {
+ DeviceSummary = new AttendanceDeviceSummary
+ {
+ Total = devices.Count,
+ EnableCount = devices.Where(x => x.Enable).Count(),
+ OnlineCount = deviceRegistries.Where(x =>
+ {
+ if (x.HeartbeatInterval <= 0)
+ {
+ return false;
+ }
+
+ return x.LastHeartbeatTime.AddSeconds(x.HeartbeatInterval * 3) >= now;
+
+ }).Count(),
+ Trend = FixTrend(devices.Where(x => x.CreateTime >= before30Day && x.CreateTime <= currentDay)
+ .GroupBy(x => x.CreateTime.Date)
+ .Select(x => new TrendDto { Date = x.Key, Count = x.Count() }), before30Day, currentDay)
+ },
+ AttendanceDetailSummary = new AttendanceDetailSummary
+ {
+ Employed = workingGainfos.Count,
+ Unemployed = leaveGainfos.Count,
+ GainfoTrend = new GainfoTrendResponse
+ {
+ EmployedTrend = FixTrend(workingGainfos.Where(x => x.CreateTime >= before7Day && x.CreateTime <= currentDay)
+ .GroupBy(x => x.CreateTime.Date)
+ .Select(x => new TrendDto { Date = x.Key, Count = x.Count() }), before7Day, currentDay),
+ UnemployedTrend = FixTrend(leaveGainfos.Where(x => x.CreateTime >= before7Day && x.CreateTime <= currentDay)
+ .GroupBy(x => x.CreateTime.Date)
+ .Select(x => new TrendDto { Date = x.Key, Count = x.Count() }), before7Day, currentDay),
+ }
+ }
+ };
+ }
+
+ private static List FixTrend(IEnumerable dtos, DateTime start, DateTime end)
+ {
+ var result = dtos.ToList();
+
+ start = start.Date;
+ end = end.Date;
+
+ var currentDate = start;
+ while (currentDate <= end)
+ {
+ if (result.Any(x => x.Date == currentDate))
+ {
+ currentDate = currentDate.AddDays(1);
+ continue;
+ }
+
+ result.Add(new TrendDto { Date = currentDate, Count = 0 });
+
+ currentDate = currentDate.AddDays(1);
+ }
+
+ return result;
+ }
+}
diff --git a/Src/Dlhis.Entity/Canteen/Enums/CanteenBusinessPlaceCatalogEnumType.cs b/Src/Dlhis.Entity/Canteen/Enums/CanteenBusinessPlaceCatalogEnumType.cs
index 9f0c4f97..80724371 100644
--- a/Src/Dlhis.Entity/Canteen/Enums/CanteenBusinessPlaceCatalogEnumType.cs
+++ b/Src/Dlhis.Entity/Canteen/Enums/CanteenBusinessPlaceCatalogEnumType.cs
@@ -20,10 +20,15 @@ public enum CanteenBusinessPlaceCatalogEnumType
[Description("食堂")]
Cafeteria = 2,
-
///
/// 超市
///
[Description("超市")]
Supermarket = 3,
+
+ ///
+ /// 水吧
+ ///
+ [Description("水吧")]
+ Bar = 4,
}
\ No newline at end of file