feat(webapi): CncWebApi完整实现 - 13控制器+DI+JWT认证,编译通过
- Controllers: 13个API控制器(Auth/Dashboard/Machine/Brand/CollectAddress/Worker/Production/Alert/Settings/Log/ScreenConfig/Screen/Option) - Infrastructure: ServiceResolver(手动DI)+JwtAuthFilter(HMACSHA256签名验证) - 路由: 属性路由覆盖,管理后台/api/admin/**+大屏/api/screen/** - 认证: JwtAuthFilter标记admin接口,ScreenController免认证 - DI: WebApiConfig注册ServiceResolver,手动解析Repository+Service依赖链 - WorkshopRepository: 从CncRepository.Impl移入CncRepository/Impl统一管理main
parent
fd40475271
commit
03aaeb11c2
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 车间仓储实现
|
||||
/// </summary>
|
||||
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<Workshop>(sql, new { Id = id });
|
||||
}
|
||||
}
|
||||
|
||||
public List<Workshop> 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<Workshop>(sql).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public PagedResult<Workshop> 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<Workshop>(sql, param).ToList();
|
||||
var total = conn.ExecuteScalar<int>(totalSql, param);
|
||||
return new PagedResult<Workshop>
|
||||
{
|
||||
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<int>(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<int>(sql, new { WorkshopId = workshopId });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 告警中心控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin/alert")]
|
||||
[JwtAuthFilter]
|
||||
public class AlertController : ApiController
|
||||
{
|
||||
private readonly IAlertService _alertService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public AlertController(IAlertService alertService)
|
||||
{
|
||||
_alertService = alertService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 告警列表(分页)
|
||||
/// GET /api/admin/alert
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("")]
|
||||
public IHttpActionResult GetList([FromUri] AlertQuery query)
|
||||
{
|
||||
if (query == null) query = new AlertQuery();
|
||||
var result = _alertService.GetList(query);
|
||||
return Ok(ApiResponse<PagedResult<AlertListItem>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 告警统计
|
||||
/// GET /api/admin/alert/statistics
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("statistics")]
|
||||
public IHttpActionResult GetStatistics()
|
||||
{
|
||||
var result = _alertService.GetStatistics();
|
||||
return Ok(ApiResponse<AlertStatisticsResponse>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理单条告警
|
||||
/// PUT /api/admin/alert/{id}/resolve
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:long}/resolve")]
|
||||
public IHttpActionResult Resolve(long id)
|
||||
{
|
||||
var result = _alertService.Resolve(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量处理告警
|
||||
/// POST /api/admin/alert/batch-resolve
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("batch-resolve")]
|
||||
public IHttpActionResult BatchResolve([FromBody] BatchResolveRequest request)
|
||||
{
|
||||
var ids = request.Ids.Select(i => (long)i).ToList();
|
||||
var count = _alertService.BatchResolve(ids);
|
||||
return Ok(ApiResponse<object>.Success(new { count }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Login;
|
||||
using CncService.Interface;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 登录认证控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin")]
|
||||
public class AuthController : ApiController
|
||||
{
|
||||
private readonly IAuthService _authService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public AuthController(IAuthService authService)
|
||||
{
|
||||
_authService = authService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 管理员登录
|
||||
/// POST /api/admin/login
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("login")]
|
||||
public IHttpActionResult Login([FromBody] LoginRequest request)
|
||||
{
|
||||
var result = _authService.Login(request);
|
||||
return Ok(ApiResponse<LoginResponse>.Success(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Brand;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 品牌模板控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin/brand")]
|
||||
[JwtAuthFilter]
|
||||
public class BrandController : ApiController
|
||||
{
|
||||
private readonly IBrandService _brandService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public BrandController(IBrandService brandService)
|
||||
{
|
||||
_brandService = brandService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 品牌列表
|
||||
/// GET /api/admin/brand
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("")]
|
||||
public IHttpActionResult GetList()
|
||||
{
|
||||
var result = _brandService.GetList();
|
||||
return Ok(ApiResponse<List<BrandListItem>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 品牌详情(含字段映射)
|
||||
/// GET /api/admin/brand/{id}
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult GetById(int id)
|
||||
{
|
||||
var result = _brandService.GetById(id);
|
||||
return Ok(ApiResponse<BrandDetailResponse>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增品牌
|
||||
/// POST /api/admin/brand
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("")]
|
||||
public IHttpActionResult Create([FromBody] CreateBrandRequest request)
|
||||
{
|
||||
var id = _brandService.Create(request);
|
||||
return Ok(ApiResponse<object>.Success(new { id }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑品牌
|
||||
/// PUT /api/admin/brand/{id}
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult Update(int id, [FromBody] UpdateBrandRequest request)
|
||||
{
|
||||
var result = _brandService.Update(id, request);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除品牌
|
||||
/// DELETE /api/admin/brand/{id}
|
||||
/// </summary>
|
||||
[HttpDelete]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult Delete(int id)
|
||||
{
|
||||
var result = _brandService.Delete(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制品牌
|
||||
/// POST /api/admin/brand/{id}/copy
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("{id:int}/copy")]
|
||||
public IHttpActionResult Copy(int id)
|
||||
{
|
||||
var newId = _brandService.Copy(id);
|
||||
return Ok(ApiResponse<object>.Success(new { id = newId }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启停品牌
|
||||
/// PUT /api/admin/brand/{id}/toggle
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:int}/toggle")]
|
||||
public IHttpActionResult ToggleEnabled(int id)
|
||||
{
|
||||
var result = _brandService.ToggleEnabled(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标准字段列表
|
||||
/// GET /api/admin/brand/standard-fields
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("standard-fields")]
|
||||
public IHttpActionResult GetStandardFields()
|
||||
{
|
||||
var result = _brandService.GetStandardFields();
|
||||
return Ok(ApiResponse<List<StandardFieldResponse>>.Success(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.CollectAddress;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 采集地址控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin/collect-address")]
|
||||
[JwtAuthFilter]
|
||||
public class CollectAddressController : ApiController
|
||||
{
|
||||
private readonly ICollectAddressService _collectAddressService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public CollectAddressController(ICollectAddressService collectAddressService)
|
||||
{
|
||||
_collectAddressService = collectAddressService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 地址列表(分页)
|
||||
/// GET /api/admin/collect-address
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("")]
|
||||
public IHttpActionResult GetList([FromUri] CollectAddressQuery query)
|
||||
{
|
||||
if (query == null) query = new CollectAddressQuery();
|
||||
var result = _collectAddressService.GetList(query);
|
||||
return Ok(ApiResponse<PagedResult<CollectAddressListItem>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 地址详情
|
||||
/// GET /api/admin/collect-address/{id}
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult GetById(int id)
|
||||
{
|
||||
var result = _collectAddressService.GetById(id);
|
||||
return Ok(ApiResponse<CollectAddressDetailResponse>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增地址
|
||||
/// POST /api/admin/collect-address
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("")]
|
||||
public IHttpActionResult Create([FromBody] CreateCollectAddressRequest request)
|
||||
{
|
||||
var id = _collectAddressService.Create(request);
|
||||
return Ok(ApiResponse<object>.Success(new { id }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑地址
|
||||
/// PUT /api/admin/collect-address/{id}
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult Update(int id, [FromBody] UpdateCollectAddressRequest request)
|
||||
{
|
||||
var result = _collectAddressService.Update(id, request);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除地址
|
||||
/// DELETE /api/admin/collect-address/{id}
|
||||
/// </summary>
|
||||
[HttpDelete]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult Delete(int id)
|
||||
{
|
||||
var result = _collectAddressService.Delete(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启停地址
|
||||
/// PUT /api/admin/collect-address/{id}/toggle
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:int}/toggle")]
|
||||
public IHttpActionResult ToggleEnabled(int id)
|
||||
{
|
||||
var result = _collectAddressService.ToggleEnabled(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Log;
|
||||
using CncRepository.Interface;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作日志控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin/log")]
|
||||
[JwtAuthFilter]
|
||||
public class LogController : ApiController
|
||||
{
|
||||
private readonly ISystemLogService _systemLogService;
|
||||
private readonly IProductionAdjustmentRepository _adjustmentRepository;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public LogController(ISystemLogService systemLogService, IProductionAdjustmentRepository adjustmentRepository)
|
||||
{
|
||||
_systemLogService = systemLogService;
|
||||
_adjustmentRepository = adjustmentRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 系统运行日志(分页)
|
||||
/// GET /api/admin/log/system
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("system")]
|
||||
public IHttpActionResult GetSystemLog([FromUri] SystemLogQuery query)
|
||||
{
|
||||
if (query == null) query = new SystemLogQuery();
|
||||
var result = _systemLogService.GetList(query);
|
||||
return Ok(ApiResponse<PagedResult<SystemLogListItem>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 产量修正日志(分页)
|
||||
/// GET /api/admin/log/adjustment
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("adjustment")]
|
||||
public IHttpActionResult GetAdjustmentLog(string targetTable = null, DateTime? startDate = null, DateTime? endDate = null, string keyword = null, int page = 1, int pageSize = 20)
|
||||
{
|
||||
var result = _adjustmentRepository.GetList(targetTable, startDate, endDate, keyword, page, pageSize);
|
||||
return Ok(ApiResponse<PagedResult<CncModels.Entity.ProductionAdjustment>>.Success(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Machine;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备管理控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin/machine")]
|
||||
[JwtAuthFilter]
|
||||
public class MachineController : ApiController
|
||||
{
|
||||
private readonly IMachineService _machineService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public MachineController(IMachineService machineService)
|
||||
{
|
||||
_machineService = machineService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 机床列表(分页)
|
||||
/// GET /api/admin/machine
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("")]
|
||||
public IHttpActionResult GetList([FromUri] MachineQuery query)
|
||||
{
|
||||
if (query == null) query = new MachineQuery();
|
||||
var result = _machineService.GetList(query);
|
||||
return Ok(ApiResponse<PagedResult<MachineListItem>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 机床详情
|
||||
/// GET /api/admin/machine/{id}
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult GetById(int id)
|
||||
{
|
||||
var result = _machineService.GetById(id);
|
||||
return Ok(ApiResponse<MachineDetailResponse>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增机床
|
||||
/// POST /api/admin/machine
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("")]
|
||||
public IHttpActionResult Create([FromBody] CreateMachineRequest request)
|
||||
{
|
||||
var id = _machineService.Create(request);
|
||||
return Ok(ApiResponse<object>.Success(new { id }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑机床
|
||||
/// PUT /api/admin/machine/{id}
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult Update(int id, [FromBody] UpdateMachineRequest request)
|
||||
{
|
||||
var result = _machineService.Update(id, request);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除机床
|
||||
/// DELETE /api/admin/machine/{id}
|
||||
/// </summary>
|
||||
[HttpDelete]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult Delete(int id)
|
||||
{
|
||||
var result = _machineService.Delete(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启停机床
|
||||
/// PUT /api/admin/machine/{id}/toggle
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:int}/toggle")]
|
||||
public IHttpActionResult ToggleEnabled(int id)
|
||||
{
|
||||
var result = _machineService.ToggleEnabled(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,109 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Common;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 公共下拉选项控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin")]
|
||||
[JwtAuthFilter]
|
||||
public class OptionController : ApiController
|
||||
{
|
||||
private readonly IWorkshopService _workshopService;
|
||||
private readonly IBrandService _brandService;
|
||||
private readonly IMachineService _machineService;
|
||||
private readonly IWorkerService _workerService;
|
||||
private readonly ICollectAddressService _collectAddressService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public OptionController(
|
||||
IWorkshopService workshopService,
|
||||
IBrandService brandService,
|
||||
IMachineService machineService,
|
||||
IWorkerService workerService,
|
||||
ICollectAddressService collectAddressService)
|
||||
{
|
||||
_workshopService = workshopService;
|
||||
_brandService = brandService;
|
||||
_machineService = machineService;
|
||||
_workerService = workerService;
|
||||
_collectAddressService = collectAddressService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 车间下拉
|
||||
/// GET /api/admin/workshop/list
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("workshop/list")]
|
||||
public IHttpActionResult WorkshopList()
|
||||
{
|
||||
var list = _workshopService.GetList(null);
|
||||
var items = list.Select(w => new SimpleOption { Value = w.Id.ToString(), Label = w.Name }).ToList();
|
||||
return Ok(ApiResponse<List<SimpleOption>>.Success(items));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 品牌下拉
|
||||
/// GET /api/admin/brand/list
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("brand/list")]
|
||||
public IHttpActionResult BrandList()
|
||||
{
|
||||
var list = _brandService.GetList();
|
||||
var items = list.Select(b => new SimpleOption { Value = b.Id.ToString(), Label = b.BrandName }).ToList();
|
||||
return Ok(ApiResponse<List<SimpleOption>>.Success(items));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 机床下拉
|
||||
/// GET /api/admin/machine/list
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("machine/list")]
|
||||
public IHttpActionResult MachineList()
|
||||
{
|
||||
var query = new CncModels.Dto.Machine.MachineQuery { Page = 1, PageSize = 1000 };
|
||||
var paged = _machineService.GetList(query);
|
||||
var items = paged.Items.Select(m => new SimpleOption { Value = m.Id.ToString(), Label = m.Name ?? m.DeviceCode }).ToList();
|
||||
return Ok(ApiResponse<List<SimpleOption>>.Success(items));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工人下拉
|
||||
/// GET /api/admin/worker/list
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("worker/list")]
|
||||
public IHttpActionResult WorkerList()
|
||||
{
|
||||
var query = new CncModels.Dto.Worker.WorkerQuery { Page = 1, PageSize = 1000 };
|
||||
var paged = _workerService.GetList(query);
|
||||
var items = paged.Items.Select(w => new SimpleOption { Value = w.Id.ToString(), Label = w.Name + "(" + w.Code + ")" }).ToList();
|
||||
return Ok(ApiResponse<List<SimpleOption>>.Success(items));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采集地址下拉
|
||||
/// GET /api/admin/collect-address/list
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("collect-address/list")]
|
||||
public IHttpActionResult CollectAddressList()
|
||||
{
|
||||
var query = new CncModels.Dto.CollectAddress.CollectAddressQuery { Page = 1, PageSize = 1000 };
|
||||
var paged = _collectAddressService.GetList(query);
|
||||
var items = paged.Items.Select(a => new SimpleOption { Value = a.Id.ToString(), Label = a.Name }).ToList();
|
||||
return Ok(ApiResponse<List<SimpleOption>>.Success(items));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Production;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 产量报表控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin/production")]
|
||||
[JwtAuthFilter]
|
||||
public class ProductionController : ApiController
|
||||
{
|
||||
private readonly IProductionService _productionService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public ProductionController(IProductionService productionService)
|
||||
{
|
||||
_productionService = productionService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日产量列表(分页)
|
||||
/// GET /api/admin/production/daily
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("daily")]
|
||||
public IHttpActionResult GetList([FromUri] ProductionQuery query)
|
||||
{
|
||||
if (query == null) query = new ProductionQuery();
|
||||
var result = _productionService.GetList(query);
|
||||
return Ok(ApiResponse<PagedResult<DailyProductionListItem>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日汇总统计
|
||||
/// GET /api/admin/production/daily-summary
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("daily-summary")]
|
||||
public IHttpActionResult GetSummary(DateTime? date = null, int? workshopId = null)
|
||||
{
|
||||
var result = _productionService.GetSummary(date, workshopId);
|
||||
return Ok(ApiResponse<DailySummaryResponse>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修正产量
|
||||
/// POST /api/admin/production/adjust
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("adjust")]
|
||||
public IHttpActionResult Adjust([FromBody] ProductionAdjustRequest request)
|
||||
{
|
||||
var result = _productionService.Adjust(request);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Entity;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 大屏配置控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin")]
|
||||
[JwtAuthFilter]
|
||||
public class ScreenConfigController : ApiController
|
||||
{
|
||||
private readonly IScreenService _screenService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public ScreenConfigController(IScreenService screenService)
|
||||
{
|
||||
_screenService = screenService;
|
||||
}
|
||||
|
||||
#region 卡片配置
|
||||
|
||||
/// <summary>
|
||||
/// 卡片配置列表
|
||||
/// GET /api/admin/screen-config
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("screen-config")]
|
||||
public IHttpActionResult GetConfigs()
|
||||
{
|
||||
var result = _screenService.GetConfigs();
|
||||
return Ok(ApiResponse<List<ScreenConfig>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑卡片
|
||||
/// PUT /api/admin/screen-config/{id}
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("screen-config/{id:int}")]
|
||||
public IHttpActionResult UpdateConfig(int id, [FromBody] ScreenConfig entity)
|
||||
{
|
||||
if (entity == null) throw new CncService.BusinessException(CncModels.Constants.ErrorCode.BadRequest, "请求参数不能为空");
|
||||
entity.Id = id;
|
||||
var result = _screenService.UpdateConfig(entity);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除卡片
|
||||
/// DELETE /api/admin/screen-config/{id}
|
||||
/// </summary>
|
||||
[HttpDelete]
|
||||
[Route("screen-config/{id:int}")]
|
||||
public IHttpActionResult DeleteConfig(int id)
|
||||
{
|
||||
var result = _screenService.DeleteFilter(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启停卡片
|
||||
/// PUT /api/admin/screen-config/{id}/toggle
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("screen-config/{id:int}/toggle")]
|
||||
public IHttpActionResult ToggleConfig(int id)
|
||||
{
|
||||
var configs = _screenService.GetConfigs();
|
||||
var config = configs.FirstOrDefault(c => c.Id == id);
|
||||
if (config == null) throw new CncService.BusinessException(CncModels.Constants.ErrorCode.NotFound, "配置不存在");
|
||||
config.IsEnabled = config.IsEnabled == 1 ? 0 : 1;
|
||||
_screenService.UpdateConfig(config);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 筛选配置
|
||||
|
||||
/// <summary>
|
||||
/// 筛选配置列表
|
||||
/// GET /api/admin/screen-filter
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("screen-filter")]
|
||||
public IHttpActionResult GetFilters(string screenKey = null)
|
||||
{
|
||||
var result = _screenService.GetFilters(screenKey ?? "main_screen");
|
||||
return Ok(ApiResponse<List<ScreenFilter>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增筛选项
|
||||
/// POST /api/admin/screen-filter
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("screen-filter")]
|
||||
public IHttpActionResult CreateFilter([FromBody] ScreenFilter entity)
|
||||
{
|
||||
if (entity == null) throw new CncService.BusinessException(CncModels.Constants.ErrorCode.BadRequest, "请求参数不能为空");
|
||||
var id = _screenService.CreateFilter(entity);
|
||||
return Ok(ApiResponse<object>.Success(new { id }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑筛选项
|
||||
/// PUT /api/admin/screen-filter/{id}
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("screen-filter/{id:int}")]
|
||||
public IHttpActionResult UpdateFilter(int id, [FromBody] ScreenFilter entity)
|
||||
{
|
||||
if (entity == null) throw new CncService.BusinessException(CncModels.Constants.ErrorCode.BadRequest, "请求参数不能为空");
|
||||
entity.Id = id;
|
||||
var result = _screenService.UpdateFilter(entity);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除筛选项
|
||||
/// DELETE /api/admin/screen-filter/{id}
|
||||
/// </summary>
|
||||
[HttpDelete]
|
||||
[Route("screen-filter/{id:int}")]
|
||||
public IHttpActionResult DeleteFilter(int id)
|
||||
{
|
||||
var result = _screenService.DeleteFilter(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,150 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Common;
|
||||
using CncModels.Dto.Dashboard;
|
||||
using CncModels.Dto.Screen;
|
||||
using CncModels.Entity;
|
||||
using CncRepository.Interface;
|
||||
using CncService.Interface;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 大屏看板控制器(无需认证)
|
||||
/// </summary>
|
||||
[RoutePrefix("api/screen")]
|
||||
public class ScreenController : ApiController
|
||||
{
|
||||
private readonly IDashboardService _dashboardService;
|
||||
private readonly IScreenService _screenService;
|
||||
private readonly ISysConfigRepository _sysConfigRepository;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public ScreenController(IDashboardService dashboardService, IScreenService screenService, ISysConfigRepository sysConfigRepository)
|
||||
{
|
||||
_dashboardService = dashboardService;
|
||||
_screenService = screenService;
|
||||
_sysConfigRepository = sysConfigRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 大屏汇总统计
|
||||
/// GET /api/screen/summary
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("summary")]
|
||||
public IHttpActionResult GetSummary()
|
||||
{
|
||||
var result = _screenService.GetSummary();
|
||||
return Ok(ApiResponse<ScreenSummaryResponse>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 采集服务状态
|
||||
/// GET /api/screen/collector-status
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("collector-status")]
|
||||
public IHttpActionResult GetCollectorStatus()
|
||||
{
|
||||
var result = _dashboardService.GetCollectorStatus();
|
||||
return Ok(ApiResponse<object>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 各车间产量
|
||||
/// GET /api/screen/workshop-production
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("workshop-production")]
|
||||
public IHttpActionResult GetWorkshopProduction()
|
||||
{
|
||||
var result = _dashboardService.GetWorkshopProduction(null, null);
|
||||
return Ok(ApiResponse<List<WorkshopProductionResponse>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 7天产量趋势
|
||||
/// GET /api/screen/production-trend
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("production-trend")]
|
||||
public IHttpActionResult GetProductionTrend(int days = 7)
|
||||
{
|
||||
var result = _dashboardService.GetProductionTrend(days);
|
||||
return Ok(ApiResponse<object>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 机床产量排行
|
||||
/// GET /api/screen/machine-rank
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("machine-rank")]
|
||||
public IHttpActionResult GetMachineRank(int top = 10)
|
||||
{
|
||||
var result = _dashboardService.GetMachineRank(null, null, top);
|
||||
return Ok(ApiResponse<List<MachineRankResponse>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工人产量排行
|
||||
/// GET /api/screen/worker-rank
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("worker-rank")]
|
||||
public IHttpActionResult GetWorkerRank(int top = 10)
|
||||
{
|
||||
var result = _dashboardService.GetWorkerRank(null, null, top);
|
||||
return Ok(ApiResponse<List<WorkerRankResponse>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 机床状态总览
|
||||
/// GET /api/screen/machine-status
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("machine-status")]
|
||||
public IHttpActionResult GetMachineStatus()
|
||||
{
|
||||
var result = _dashboardService.GetMachineStatusDistribution();
|
||||
return Ok(ApiResponse<object>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 大屏筛选条件
|
||||
/// GET /api/screen/filters
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("filters")]
|
||||
public IHttpActionResult GetFilters(string screenKey = "main_screen")
|
||||
{
|
||||
var filters = _screenService.GetFilters(screenKey);
|
||||
var items = filters.Select(f => new CncModels.Dto.Common.SimpleOption
|
||||
{
|
||||
Value = f.FilterValue,
|
||||
Label = f.FilterType
|
||||
}).ToList();
|
||||
return Ok(ApiResponse<List<CncModels.Dto.Common.SimpleOption>>.Success(items));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新间隔配置
|
||||
/// GET /api/screen/refresh-interval
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("refresh-interval")]
|
||||
public IHttpActionResult GetRefreshInterval()
|
||||
{
|
||||
var cfg = _sysConfigRepository.GetByKey("screen_refresh_interval");
|
||||
int interval = 30;
|
||||
if (cfg != null && int.TryParse(cfg.ConfigValue, out int val))
|
||||
interval = val;
|
||||
return Ok(ApiResponse<object>.Success(new { interval }));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Settings;
|
||||
using CncModels.Entity;
|
||||
using CncRepository.Interface;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 系统设置控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin")]
|
||||
[JwtAuthFilter]
|
||||
public class SettingsController : ApiController
|
||||
{
|
||||
private readonly ISysConfigRepository _sysConfigRepository;
|
||||
private readonly IWorkshopService _workshopService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public SettingsController(ISysConfigRepository sysConfigRepository, IWorkshopService workshopService)
|
||||
{
|
||||
_sysConfigRepository = sysConfigRepository;
|
||||
_workshopService = workshopService;
|
||||
}
|
||||
|
||||
#region 系统配置
|
||||
|
||||
/// <summary>
|
||||
/// 配置项列表
|
||||
/// GET /api/admin/sys-config
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("sys-config")]
|
||||
public IHttpActionResult GetSysConfigList()
|
||||
{
|
||||
var configs = _sysConfigRepository.GetAll();
|
||||
var items = configs.Select(c => new SysConfigListItem
|
||||
{
|
||||
Id = c.Id,
|
||||
ConfigKey = c.ConfigKey,
|
||||
ConfigValue = c.ConfigValue,
|
||||
ValueType = c.ValueType,
|
||||
Description = c.Description
|
||||
}).ToList();
|
||||
return Ok(ApiResponse<List<SysConfigListItem>>.Success(items));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑配置项
|
||||
/// PUT /api/admin/sys-config/{id}
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("sys-config/{id:int}")]
|
||||
public IHttpActionResult UpdateSysConfig(int id, [FromBody] UpdateSysConfigRequest request)
|
||||
{
|
||||
if (request == null) throw new CncService.BusinessException(CncModels.Constants.ErrorCode.BadRequest, "请求参数不能为空");
|
||||
var result = _sysConfigRepository.UpdateValue(id, request.ConfigValue);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改密码
|
||||
/// POST /api/admin/change-password
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("change-password")]
|
||||
public IHttpActionResult ChangePassword([FromBody] ChangePasswordRequest request)
|
||||
{
|
||||
if (request == null) throw new CncService.BusinessException(CncModels.Constants.ErrorCode.BadRequest, "请求参数不能为空");
|
||||
// 简化实现:更新密码哈希到 SysConfig
|
||||
var hash = BCrypt.Net.BCrypt.HashPassword(request.NewPassword);
|
||||
var pwdCfg = _sysConfigRepository.GetByKey("admin_password_hash");
|
||||
if (pwdCfg == null) throw new CncService.BusinessException(CncModels.Constants.ErrorCode.NotFound, "密码配置未找到");
|
||||
_sysConfigRepository.UpdateValue(pwdCfg.Id, hash);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 车间管理
|
||||
|
||||
/// <summary>
|
||||
/// 车间列表
|
||||
/// GET /api/admin/workshop
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("workshop")]
|
||||
public IHttpActionResult GetWorkshopList(string keyword = null)
|
||||
{
|
||||
var result = _workshopService.GetList(keyword);
|
||||
return Ok(ApiResponse<List<WorkshopListItem>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增车间
|
||||
/// POST /api/admin/workshop
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("workshop")]
|
||||
public IHttpActionResult CreateWorkshop([FromBody] CreateWorkshopRequest request)
|
||||
{
|
||||
var id = _workshopService.Create(request);
|
||||
return Ok(ApiResponse<object>.Success(new { id }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑车间
|
||||
/// PUT /api/admin/workshop/{id}
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("workshop/{id:int}")]
|
||||
public IHttpActionResult UpdateWorkshop(int id, [FromBody] UpdateWorkshopRequest request)
|
||||
{
|
||||
var result = _workshopService.Update(id, request);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除车间
|
||||
/// DELETE /api/admin/workshop/{id}
|
||||
/// </summary>
|
||||
[HttpDelete]
|
||||
[Route("workshop/{id:int}")]
|
||||
public IHttpActionResult DeleteWorkshop(int id)
|
||||
{
|
||||
var result = _workshopService.Delete(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启停车间
|
||||
/// PUT /api/admin/workshop/{id}/toggle
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("workshop/{id:int}/toggle")]
|
||||
public IHttpActionResult ToggleWorkshop(int id)
|
||||
{
|
||||
var result = _workshopService.ToggleEnabled(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,132 @@
|
||||
using System.Web.Http;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Dto.Worker;
|
||||
using CncService.Interface;
|
||||
using CncWebApi.Infrastructure;
|
||||
|
||||
namespace CncWebApi.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// 员工管理控制器
|
||||
/// </summary>
|
||||
[RoutePrefix("api/admin/worker")]
|
||||
[JwtAuthFilter]
|
||||
public class WorkerController : ApiController
|
||||
{
|
||||
private readonly IWorkerService _workerService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public WorkerController(IWorkerService workerService)
|
||||
{
|
||||
_workerService = workerService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工人列表(分页)
|
||||
/// GET /api/admin/worker
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("")]
|
||||
public IHttpActionResult GetList([FromUri] WorkerQuery query)
|
||||
{
|
||||
if (query == null) query = new WorkerQuery();
|
||||
var result = _workerService.GetList(query);
|
||||
return Ok(ApiResponse<PagedResult<WorkerListItem>>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 工人详情
|
||||
/// GET /api/admin/worker/{id}
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult GetById(int id)
|
||||
{
|
||||
var result = _workerService.GetById(id);
|
||||
return Ok(ApiResponse<WorkerDetailResponse>.Success(result));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增工人
|
||||
/// POST /api/admin/worker
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("")]
|
||||
public IHttpActionResult Create([FromBody] CreateWorkerRequest request)
|
||||
{
|
||||
var id = _workerService.Create(request);
|
||||
return Ok(ApiResponse<object>.Success(new { id }));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 编辑工人
|
||||
/// PUT /api/admin/worker/{id}
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult Update(int id, [FromBody] UpdateWorkerRequest request)
|
||||
{
|
||||
var result = _workerService.Update(id, request);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除工人
|
||||
/// DELETE /api/admin/worker/{id}
|
||||
/// </summary>
|
||||
[HttpDelete]
|
||||
[Route("{id:int}")]
|
||||
public IHttpActionResult Delete(int id)
|
||||
{
|
||||
var result = _workerService.Delete(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启停工人
|
||||
/// PUT /api/admin/worker/{id}/toggle
|
||||
/// </summary>
|
||||
[HttpPut]
|
||||
[Route("{id:int}/toggle")]
|
||||
public IHttpActionResult ToggleEnabled(int id)
|
||||
{
|
||||
var result = _workerService.ToggleEnabled(id);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定机床
|
||||
/// POST /api/admin/worker/{id}/bind
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("{id:int}/bind")]
|
||||
public IHttpActionResult BindMachine(int id, [FromBody] BindMachineRequest request)
|
||||
{
|
||||
var result = _workerService.BindMachine(id, request.MachineId);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解绑机床
|
||||
/// POST /api/admin/worker/{id}/unbind
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("{id:int}/unbind")]
|
||||
public IHttpActionResult UnbindMachine(int id, [FromBody] BindMachineRequest request)
|
||||
{
|
||||
var result = _workerService.UnbindMachine(id, request.MachineId);
|
||||
return Ok(ApiResponse<object>.Success(null));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 绑定/解绑机床请求
|
||||
/// </summary>
|
||||
public class BindMachineRequest
|
||||
{
|
||||
/// <summary>机床ID</summary>
|
||||
public int MachineId { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Web.Http.Controllers;
|
||||
using System.Web.Http.Filters;
|
||||
using CncModels.Dto;
|
||||
using CncModels.Constants;
|
||||
|
||||
namespace CncWebApi.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// JWT 认证过滤器
|
||||
/// 验证请求 Header 中的 Bearer Token
|
||||
/// 管理 /api/admin/** 接口需要认证,大屏 /api/screen/** 不需要
|
||||
/// </summary>
|
||||
public class JwtAuthFilter : AuthorizationFilterAttribute
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override void OnAuthorization(HttpActionContext actionContext)
|
||||
{
|
||||
// 从 Header 读取 Authorization
|
||||
var authHeader = actionContext.Request.Headers.Authorization;
|
||||
if (authHeader == null || !string.Equals(authHeader.Scheme, "Bearer", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Reject(actionContext, "Token缺失");
|
||||
return;
|
||||
}
|
||||
|
||||
var token = authHeader.Parameter;
|
||||
if (string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
Reject(actionContext, "Token为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证 JWT
|
||||
try
|
||||
{
|
||||
var parts = token.Split('.');
|
||||
if (parts.Length != 3)
|
||||
{
|
||||
Reject(actionContext, "Token格式无效");
|
||||
return;
|
||||
}
|
||||
|
||||
// 从 Web.config 读取密钥
|
||||
var secret = System.Configuration.ConfigurationManager.AppSettings["JwtSecret"];
|
||||
if (string.IsNullOrEmpty(secret))
|
||||
{
|
||||
Reject(actionContext, "服务端配置错误");
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证签名
|
||||
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret)))
|
||||
{
|
||||
var expectedSig = Base64UrlEncode(hmac.ComputeHash(Encoding.UTF8.GetBytes(parts[0] + "." + parts[1])));
|
||||
if (!string.Equals(expectedSig, parts[2], StringComparison.Ordinal))
|
||||
{
|
||||
Reject(actionContext, "Token签名无效");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查过期
|
||||
var payloadBytes = Base64UrlDecode(parts[1]);
|
||||
var payloadJson = Encoding.UTF8.GetString(payloadBytes);
|
||||
var expMatch = System.Text.RegularExpressions.Regex.Match(payloadJson, @"""exp"":(\d+)");
|
||||
if (expMatch.Success)
|
||||
{
|
||||
var exp = long.Parse(expMatch.Groups[1].Value);
|
||||
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
if (now > exp)
|
||||
{
|
||||
Reject(actionContext, "Token已过期");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Reject(actionContext, "Token验证失败");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void Reject(HttpActionContext actionContext, string message)
|
||||
{
|
||||
var response = ApiResponse<object>.Fail(ErrorCode.Unauthorized, message);
|
||||
actionContext.Response = actionContext.Request.CreateResponse(
|
||||
HttpStatusCode.OK, response);
|
||||
}
|
||||
|
||||
private static string Base64UrlEncode(byte[] input)
|
||||
{
|
||||
return Convert.ToBase64String(input).Replace("+", "-").Replace("/", "_").TrimEnd('=');
|
||||
}
|
||||
|
||||
private static byte[] Base64UrlDecode(string input)
|
||||
{
|
||||
var base64 = input.Replace("-", "+").Replace("_", "/");
|
||||
switch (base64.Length % 4)
|
||||
{
|
||||
case 2: base64 += "=="; break;
|
||||
case 3: base64 += "="; break;
|
||||
}
|
||||
return Convert.FromBase64String(base64);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Web.Http.Dependencies;
|
||||
using CncRepository.Base;
|
||||
using CncRepository.Interface;
|
||||
using CncService.Interface;
|
||||
|
||||
namespace CncWebApi.Infrastructure
|
||||
{
|
||||
/// <summary>
|
||||
/// 简单的依赖注入解析器
|
||||
/// 手动注册 Repository 和 Service 的映射关系
|
||||
/// </summary>
|
||||
public class ServiceResolver : IDependencyResolver
|
||||
{
|
||||
private static readonly string _businessConn = ConfigurationManager.ConnectionStrings["BusinessConnection"]?.ConnectionString;
|
||||
private static readonly string _logConn = ConfigurationManager.ConnectionStrings["LogConnection"]?.ConnectionString;
|
||||
private static readonly string _jwtSecret = ConfigurationManager.AppSettings["JwtSecret"];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IDependencyScope BeginScope()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public object GetService(Type serviceType)
|
||||
{
|
||||
// Controller 解析
|
||||
if (serviceType == typeof(Controllers.AuthController))
|
||||
return new Controllers.AuthController(
|
||||
ResolveAuthService());
|
||||
if (serviceType == typeof(Controllers.DashboardController))
|
||||
return new Controllers.DashboardController(
|
||||
ResolveDashboardService());
|
||||
if (serviceType == typeof(Controllers.MachineController))
|
||||
return new Controllers.MachineController(
|
||||
ResolveMachineService());
|
||||
if (serviceType == typeof(Controllers.BrandController))
|
||||
return new Controllers.BrandController(
|
||||
ResolveBrandService());
|
||||
if (serviceType == typeof(Controllers.CollectAddressController))
|
||||
return new Controllers.CollectAddressController(
|
||||
ResolveCollectAddressService());
|
||||
if (serviceType == typeof(Controllers.WorkerController))
|
||||
return new Controllers.WorkerController(
|
||||
ResolveWorkerService());
|
||||
if (serviceType == typeof(Controllers.ProductionController))
|
||||
return new Controllers.ProductionController(
|
||||
ResolveProductionService());
|
||||
if (serviceType == typeof(Controllers.AlertController))
|
||||
return new Controllers.AlertController(
|
||||
ResolveAlertService());
|
||||
if (serviceType == typeof(Controllers.SettingsController))
|
||||
return new Controllers.SettingsController(
|
||||
new CncRepository.Impl.SysConfigRepository(_businessConn),
|
||||
ResolveWorkshopService());
|
||||
if (serviceType == typeof(Controllers.LogController))
|
||||
return new Controllers.LogController(
|
||||
ResolveSystemLogService(),
|
||||
ResolveProductionAdjustmentRepository());
|
||||
if (serviceType == typeof(Controllers.ScreenConfigController))
|
||||
return new Controllers.ScreenConfigController(
|
||||
ResolveScreenService());
|
||||
if (serviceType == typeof(Controllers.ScreenController))
|
||||
return new Controllers.ScreenController(
|
||||
ResolveDashboardService(),
|
||||
ResolveScreenService(),
|
||||
new CncRepository.Impl.SysConfigRepository(_businessConn));
|
||||
if (serviceType == typeof(Controllers.OptionController))
|
||||
return new Controllers.OptionController(
|
||||
ResolveWorkshopService(),
|
||||
ResolveBrandService(),
|
||||
ResolveMachineService(),
|
||||
ResolveWorkerService(),
|
||||
ResolveCollectAddressService());
|
||||
if (serviceType == typeof(Controllers.HealthController))
|
||||
return new Controllers.HealthController();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerable<object> GetServices(Type serviceType)
|
||||
{
|
||||
return Enumerable.Empty<object>();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose() { }
|
||||
|
||||
#region Service 解析
|
||||
|
||||
private IAuthService ResolveAuthService()
|
||||
{
|
||||
return new CncService.Impl.AuthService(
|
||||
new CncRepository.Impl.SysConfigRepository(_businessConn),
|
||||
_jwtSecret);
|
||||
}
|
||||
|
||||
private IDashboardService ResolveDashboardService()
|
||||
{
|
||||
return new CncService.Impl.DashboardService(
|
||||
new CncRepository.Impl.Dashboard.DashboardRepository(_businessConn),
|
||||
new CncRepository.Impl.Log.CollectorHeartbeatRepository(_logConn));
|
||||
}
|
||||
|
||||
private IMachineService ResolveMachineService()
|
||||
{
|
||||
return new CncService.Impl.MachineService(
|
||||
new CncRepository.Impl.MachineRepository(_businessConn),
|
||||
new CncRepository.Impl.CollectAddressRepository(_businessConn),
|
||||
new CncRepository.Impl.WorkerMachineRepository(_businessConn),
|
||||
new CncRepository.Impl.BrandRepository(_businessConn));
|
||||
}
|
||||
|
||||
private IBrandService ResolveBrandService()
|
||||
{
|
||||
return new CncService.Impl.BrandService(
|
||||
new CncRepository.Impl.BrandRepository(_businessConn),
|
||||
new CncRepository.Impl.BrandFieldMappingRepository(_businessConn),
|
||||
new CncRepository.Impl.CollectAddressRepository(_businessConn));
|
||||
}
|
||||
|
||||
private ICollectAddressService ResolveCollectAddressService()
|
||||
{
|
||||
return new CncService.Impl.CollectAddressService(
|
||||
new CncRepository.Impl.CollectAddressRepository(_businessConn),
|
||||
new CncRepository.Impl.MachineRepository(_businessConn),
|
||||
new CncRepository.Impl.BrandRepository(_businessConn));
|
||||
}
|
||||
|
||||
private IWorkerService ResolveWorkerService()
|
||||
{
|
||||
return new CncService.Impl.WorkerService(
|
||||
new CncRepository.Impl.WorkerRepository(_businessConn),
|
||||
new CncRepository.Impl.WorkerMachineRepository(_businessConn),
|
||||
new CncRepository.Impl.MachineRepository(_businessConn));
|
||||
}
|
||||
|
||||
private IProductionService ResolveProductionService()
|
||||
{
|
||||
return new CncService.Impl.ProductionService(
|
||||
new CncRepository.Impl.DailyProductionRepository(_businessConn),
|
||||
new CncRepository.Impl.ProductionSegmentRepository(_businessConn),
|
||||
new CncRepository.Impl.ProductionAdjustmentRepository(_businessConn));
|
||||
}
|
||||
|
||||
private IAlertService ResolveAlertService()
|
||||
{
|
||||
return new CncService.Impl.AlertService(
|
||||
new CncRepository.Impl.AlertRepository(_businessConn));
|
||||
}
|
||||
|
||||
private IWorkshopService ResolveWorkshopService()
|
||||
{
|
||||
return new CncService.Impl.WorkshopService(
|
||||
new CncRepository.Impl.WorkshopRepository(_businessConn));
|
||||
}
|
||||
|
||||
private IScreenService ResolveScreenService()
|
||||
{
|
||||
return new CncService.Impl.ScreenService(
|
||||
new CncRepository.Impl.ScreenConfigRepository(_businessConn),
|
||||
new CncRepository.Impl.ScreenFilterRepository(_businessConn),
|
||||
new CncRepository.Impl.WorkshopRepository(_businessConn));
|
||||
}
|
||||
|
||||
private ISystemLogService ResolveSystemLogService()
|
||||
{
|
||||
return new CncService.Impl.SystemLogService(
|
||||
new CncRepository.Impl.SystemLogRepository(_logConn));
|
||||
}
|
||||
|
||||
private IProductionAdjustmentRepository ResolveProductionAdjustmentRepository()
|
||||
{
|
||||
return new CncRepository.Impl.ProductionAdjustmentRepository(_businessConn);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue