using Admin.NET.Plugin.AiDOP.Dto.S0.Manufacturing; using Admin.NET.Plugin.AiDOP.Entity.S0.Manufacturing; using Admin.NET.Plugin.AiDOP.Infrastructure; namespace Admin.NET.Plugin.AiDOP.Controllers.S0.Manufacturing; [ApiController] [Route("api/s0/manufacturing/sop-documents")] [NonUnify] public class AdoS0MfgSopDocumentsController : ControllerBase { private readonly SqlSugarRepository _rep; public AdoS0MfgSopDocumentsController(SqlSugarRepository rep) { _rep = rep; } [HttpGet] public async Task GetPagedAsync([FromQuery] AdoS0MfgSopDocumentQueryDto q) { if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!; var page = q.Page; var pageSize = q.PageSize; (page, pageSize) = PagingGuard.Normalize(page, pageSize); // 去 domain 化(S0-SOP-DOMAIN-DECOUPLING-FIX):列表可见性只由 tenant_id 决定。 // 原先 `x.Domain == q.Domain` 会把本租户数据挡在外面——前端在无 Type=501 工厂时 // 会把公司雪花 Id 当 Domain 传入,与业务表的 legacy Domain(8010) 永不相等。 var baseQuery = _rep.ScopedTo(tenantId) .WhereIF(!string.IsNullOrWhiteSpace(q.Keyword), x => (x.Line != null && x.Line.Contains(q.Keyword!)) || (x.ItemNum != null && x.ItemNum.Contains(q.Keyword!)) || (x.Op != null && x.Op.Contains(q.Keyword!)) || (x.Path != null && x.Path.Contains(q.Keyword!)) || (x.Descr != null && x.Descr.Contains(q.Keyword!)) || (x.Rev != null && x.Rev.Contains(q.Keyword!))); var total = await baseQuery.CountAsync(); // 左联仅用于展示字段(Line/Op/imgType),主表字段仍可 CRUD。 // 关联口径一律 tenant_id + 业务键:Domain 是 legacy 兼容字段,同租户内不同表的 Domain // 取值可能不一致(如 SOP 用组织 Id、LineMaster 用 8010),用它做关联会导致展示列解析不出来; // 用 tenant_id 兜住跨租户,业务键保证语义正确。 var list = await baseQuery .LeftJoin((qsi, it) => qsi.TenantId == it.TenantId && qsi.ImageTypeID == it.ImageTypeID) .LeftJoin((qsi, it, lm) => qsi.TenantId == lm.TenantId && qsi.Line == lm.Line) .LeftJoin((qsi, it, lm, rd) => qsi.TenantId == rd.TenantId && qsi.ItemNum == rd.MaterialCode && qsi.Op == rd.OperationCode) .OrderByDescending((qsi, it, lm, rd) => qsi.Id) .Select((qsi, it, lm, rd) => new { id = qsi.Id, line = qsi.Line, lineDisplay = qsi.Line == null ? "" : (lm.Line + " " + (lm.Describe ?? "")), itemNum = qsi.ItemNum, op = qsi.Op, opDisplay = qsi.Op == null ? "" : (rd.OperationCode + " " + (rd.OperationDescription ?? "")), imageTypeID = qsi.ImageTypeID, imgType = it.Descr, path = qsi.Path, descr = qsi.Descr, rev = qsi.Rev, sortID = qsi.SortID, domain = qsi.Domain }) .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); return Ok(new { total, page, pageSize, list }); } [HttpGet("{id:long}")] public async Task GetAsync(long id) { if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!; var item = await _rep.ByIdScopedAsync(id, tenantId); return item == null ? NotFound() : Ok(item); } [HttpPost] public async Task CreateAsync([FromBody] AdoS0MfgSopDocumentUpsertDto dto) { if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!; var entity = new AdoS0QualitySegmentImage { TenantId = tenantId, Domain = dto.Domain.Trim(), Line = dto.Line, ItemNum = dto.ItemNum, Op = dto.Op, ImageTypeID = dto.ImageTypeID, Path = dto.Path, Descr = dto.Descr, Rev = dto.Rev, SortID = dto.SortID }; await _rep.AsInsertable(entity).ExecuteReturnEntityAsync(); return Ok(entity); } [HttpPut("{id:long}")] public async Task UpdateAsync(long id, [FromBody] AdoS0MfgSopDocumentUpsertDto dto) { if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!; var entity = await _rep.ByIdScopedAsync(id, tenantId); if (entity == null) return NotFound(); entity.Domain = dto.Domain.Trim(); entity.Line = dto.Line; entity.ItemNum = dto.ItemNum; entity.Op = dto.Op; entity.ImageTypeID = dto.ImageTypeID; entity.Path = dto.Path; entity.Descr = dto.Descr; entity.Rev = dto.Rev; entity.SortID = dto.SortID; await _rep.AsUpdateable(entity).ExecuteCommandAsync(); return Ok(entity); } [HttpDelete("{id:long}")] public async Task DeleteAsync(long id) { if (!AdoS0TenantScope.TryResolveRequired(out var tenantId, out var tenantError)) return tenantError!; var item = await _rep.ByIdScopedAsync(id, tenantId); if (item == null) return NotFound(); await _rep.DeleteAsync(item); return Ok(new { message = "删除成功" }); } }