Files
Evergreen-Health/Evergreen.Health.Application/Health/Integrations/Ib43/Ib43LocalBinding.cs
T
2026-11-11 16:11:41 +08:00

56 lines
3.0 KiB
C#

using Evergreen.Health.Application.Health.Entities;
using SqlSugar;
namespace Evergreen.Health.Application.Health.Integrations.Ib43;
// 仅由本地维护程序调用;不是 Controller,也不注册 HTTP 路由。
public sealed class Ib43LocalBinding(ISqlSugarClient db, TimeProvider clock)
{
public async Task<HealthIb43Binding> Run(string phone, Ib43Options options, string actor, bool apply)
{
var device = options.Devices.SingleOrDefault(d => d.ProductKey == "evergreen-test" && d.SerialNumber == "IB43SIM001");
if (device?.Simulation != true) throw new InvalidOperationException("模拟设备白名单不匹配,已停止。");
var users = await db.Queryable<HealthUser>().Where(u => u.Phone == phone && !u.IsDelete &&
u.Status == HealthUserStatus.Enabled).Select(u => new { u.Id }).ToListAsync();
if (users.Count != 1) throw new InvalidOperationException("未找到唯一且已启用的健康账号,已停止。");
var key = Ib43DataRepository.DeviceKey(device.ProductKey, device.SerialNumber);
var slot = key + ".left";
var existing = await db.Queryable<HealthIb43Binding>().Where(b => b.ActiveSlot == slot).FirstAsync();
if (existing != null)
{
if (existing.UserId != users[0].Id || !existing.Simulation || existing.EndedAtMs != null)
throw new InvalidOperationException("左侧已被其他用户或非模拟绑定占用,未覆盖或解绑。");
return existing;
}
var binding = new HealthIb43Binding
{
DeviceKey = key, ProductKey = device.ProductKey, SerialNumber = device.SerialNumber,
Side = "left", ActiveSlot = slot, UserId = users[0].Id, BedName = "IB43模拟床垫左侧",
Simulation = true, StartedAtMs = clock.GetUtcNow().ToUnixTimeMilliseconds(), AssignedBy = 0
};
if (!apply) return binding;
if (string.IsNullOrWhiteSpace(actor) || actor.Length > 200) throw new InvalidOperationException("维护操作者信息不合法。");
var stage = "binding";
await db.Ado.BeginTranAsync();
try
{
await db.Insertable(binding).ExecuteCommandAsync();
stage = "audit";
await db.Insertable(new HealthIb43MaintenanceAudit
{
Id = Guid.NewGuid().ToString("N"), BindingId = binding.Id, UserId = binding.UserId,
Actor = actor, OccurredAtMs = binding.StartedAtMs, Operation = "local-bind-simulator-left"
}).ExecuteCommandAsync();
stage = "commit";
await db.Ado.CommitTranAsync();
}
catch (Exception error)
{
await db.Ado.RollbackTranAsync();
var code = error is MySqlConnector.MySqlException mysql ? $" MySQL {mysql.Number}" : "";
throw new InvalidOperationException($"绑定事务失败 ({stage}, {error.GetType().Name}{code}),请重新预检确认数据库状态。", error);
}
return binding;
}
}