diff --git a/src/CncRepository/Impl/WorkshopRepository.cs b/src/CncRepository/Impl/WorkshopRepository.cs
new file mode 100644
index 0000000..3c7f126
--- /dev/null
+++ b/src/CncRepository/Impl/WorkshopRepository.cs
@@ -0,0 +1,111 @@
+using System.Collections.Generic;
+using System.Linq;
+using Dapper;
+using CncModels.Entity;
+using CncRepository.Base;
+using CncRepository.Interface;
+using System.Data;
+using CncModels.Dto;
+
+namespace CncRepository.Impl
+{
+ ///
+ /// 车间仓储实现
+ ///
+ public class WorkshopRepository : BusinessRepository, IWorkshopRepository
+ {
+ public WorkshopRepository(string connectionString) : base(connectionString) { }
+
+ public Workshop GetById(int id)
+ {
+ using (var conn = CreateConnection())
+ {
+ var sql = @"SELECT Id as Id, Name as Name, SortOrder as SortOrder, IsEnabled as IsEnabled, CreatedAt as CreatedAt, UpdatedAt as UpdatedAt FROM cnc_workshop WHERE Id = @Id";
+ return conn.QuerySingleOrDefault(sql, new { Id = id });
+ }
+ }
+
+ public List GetAll()
+ {
+ using (var conn = CreateConnection())
+ {
+ var sql = @"SELECT Id as Id, Name as Name, SortOrder as SortOrder, IsEnabled as IsEnabled, CreatedAt as CreatedAt, UpdatedAt as UpdatedAt FROM cnc_workshop ORDER BY SortOrder ASC";
+ return conn.Query(sql).ToList();
+ }
+ }
+
+ public PagedResult GetList(string keyword)
+ {
+ using (var conn = CreateConnection())
+ {
+ var where = string.Empty;
+ var param = new DynamicParameters();
+ if (!string.IsNullOrWhiteSpace(keyword))
+ {
+ where = " WHERE Name LIKE @Keyword";
+ param.Add("Keyword", $"%{keyword}%");
+ }
+ var limit = 20;
+ var sql = $@"SELECT Id as Id, Name as Name, SortOrder as SortOrder, IsEnabled as IsEnabled, CreatedAt as CreatedAt, UpdatedAt as UpdatedAt
+ FROM cnc_workshop {where} ORDER BY SortOrder ASC LIMIT {limit} OFFSET 0";
+ var totalSql = $@"SELECT COUNT(*) FROM cnc_workshop {where}";
+ var items = conn.Query(sql, param).ToList();
+ var total = conn.ExecuteScalar(totalSql, param);
+ return new PagedResult
+ {
+ Items = items,
+ Total = total,
+ Page = 1,
+ PageSize = limit
+ };
+ }
+ }
+
+ public int Create(Workshop entity)
+ {
+ using (var conn = CreateConnection())
+ {
+ var sql = @"INSERT INTO cnc_workshop (Name, SortOrder, IsEnabled, CreatedAt, UpdatedAt)
+ VALUES (@Name, @SortOrder, @IsEnabled, @CreatedAt, @UpdatedAt);
+ SELECT LAST_INSERT_ID();";
+ return conn.QuerySingle(sql, entity);
+ }
+ }
+
+ public bool Update(Workshop entity)
+ {
+ using (var conn = CreateConnection())
+ {
+ var sql = @"UPDATE cnc_workshop SET Name = @Name, SortOrder = @SortOrder, IsEnabled = @IsEnabled, UpdatedAt = @UpdatedAt WHERE Id = @Id";
+ return conn.Execute(sql, entity) > 0;
+ }
+ }
+
+ public bool Delete(int id)
+ {
+ using (var conn = CreateConnection())
+ {
+ var sql = @"DELETE FROM cnc_workshop WHERE Id = @Id";
+ return conn.Execute(sql, new { Id = id }) > 0;
+ }
+ }
+
+ public bool ToggleEnabled(int id)
+ {
+ using (var conn = CreateConnection())
+ {
+ var sql = @"UPDATE cnc_workshop SET IsEnabled = CASE WHEN IsEnabled = 1 THEN 0 ELSE 1 END, UpdatedAt = NOW() WHERE Id = @Id";
+ return conn.Execute(sql, new { Id = id }) > 0;
+ }
+ }
+
+ public int GetMachineCount(int workshopId)
+ {
+ using (var conn = CreateConnection())
+ {
+ var sql = @"SELECT COUNT(*) FROM cnc_machine WHERE WorkshopId = @WorkshopId";
+ return conn.ExecuteScalar(sql, new { WorkshopId = workshopId });
+ }
+ }
+ }
+}
diff --git a/src/CncWebApi/App_Start/WebApiConfig.cs b/src/CncWebApi/App_Start/WebApiConfig.cs
index ebeb7dd..2672acc 100644
--- a/src/CncWebApi/App_Start/WebApiConfig.cs
+++ b/src/CncWebApi/App_Start/WebApiConfig.cs
@@ -1,5 +1,7 @@
using System.Web.Http;
using System.Web.Http.Cors;
+using CncWebApi.Filters;
+using CncWebApi.Infrastructure;
namespace CncWebApi.App_Start
{
@@ -15,16 +17,17 @@ namespace CncWebApi.App_Start
/// HTTP配置对象
public static void Register(HttpConfiguration config)
{
+ // 依赖注入解析器
+ config.DependencyResolver = new ServiceResolver();
+
// 跨域配置(局域网场景,允许所有来源)
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
// 路由注册
- // 默认路由模板:api/{controller}/{id}
- // 各Controller使用 [RoutePrefix] + [Route] 属性路由覆盖此默认
config.MapHttpAttributeRoutes();
// 全局异常过滤器
- config.Filters.Add(new Filters.GlobalExceptionFilter());
+ config.Filters.Add(new GlobalExceptionFilter());
// 统一JSON序列化设置
config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling =
diff --git a/src/CncWebApi/Controllers/AlertController.cs b/src/CncWebApi/Controllers/AlertController.cs
new file mode 100644
index 0000000..f5d0a67
--- /dev/null
+++ b/src/CncWebApi/Controllers/AlertController.cs
@@ -0,0 +1,78 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Web.Http;
+using CncModels.Dto;
+using CncModels.Dto.Alert;
+using CncService.Interface;
+using CncWebApi.Infrastructure;
+
+namespace CncWebApi.Controllers
+{
+ ///
+ /// 告警中心控制器
+ ///
+ [RoutePrefix("api/admin/alert")]
+ [JwtAuthFilter]
+ public class AlertController : ApiController
+ {
+ private readonly IAlertService _alertService;
+
+ ///
+ /// 构造函数
+ ///
+ public AlertController(IAlertService alertService)
+ {
+ _alertService = alertService;
+ }
+
+ ///
+ /// 告警列表(分页)
+ /// GET /api/admin/alert
+ ///
+ [HttpGet]
+ [Route("")]
+ public IHttpActionResult GetList([FromUri] AlertQuery query)
+ {
+ if (query == null) query = new AlertQuery();
+ var result = _alertService.GetList(query);
+ return Ok(ApiResponse>.Success(result));
+ }
+
+ ///
+ /// 告警统计
+ /// GET /api/admin/alert/statistics
+ ///
+ [HttpGet]
+ [Route("statistics")]
+ public IHttpActionResult GetStatistics()
+ {
+ var result = _alertService.GetStatistics();
+ return Ok(ApiResponse.Success(result));
+ }
+
+ ///
+ /// 处理单条告警
+ /// PUT /api/admin/alert/{id}/resolve
+ ///
+ [HttpPut]
+ [Route("{id:long}/resolve")]
+ public IHttpActionResult Resolve(long id)
+ {
+ var result = _alertService.Resolve(id);
+ return Ok(ApiResponse