| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- using Admin.NET.Plugin.AiDOP.MaterialWarehouse.Dto;
- namespace Admin.NET.Plugin.AiDOP.MaterialWarehouse;
- /// <summary>
- /// S5 生产领料单 只读 list 服务。
- ///
- /// 数据源:DOP 数据中台标准层 mdp_std_production_issue(头级)。
- /// 由 ProductionIssueMdpSyncService 从 aidopdev.NbrMaster Type='SM' 同步标准化而来。
- ///
- /// 本服务仅 SELECT:无新增/编辑/删除/发料确认/库存事务/状态流转/明细。
- /// 领料单为头级列表(一单一行),不 JOIN 明细,无重复。
- /// </summary>
- [ApiDescriptionSettings(Order = 305, Description = "生产领料单")]
- [Route("api/ProductionIssue")]
- [NonUnify]
- public class ProductionIssueService : IDynamicApiController, ITransient
- {
- /// <summary>主/系统租户哨兵:超管未选择目标租户时其 JWT TenantId 即此值,拒绝作为业务租户。</summary>
- private const long MainTenantId = 1300000000001L;
- private readonly ISqlSugarClient _db;
- private readonly UserManager _userManager;
- public ProductionIssueService(ISqlSugarClient db, UserManager userManager)
- {
- _db = db;
- _userManager = userManager;
- }
- /// <summary>严格可信租户解析:只来自认证后 JWT;无 Token(<=0) 或超管未选主租户 → 拒绝;不读前端 tenantId、无默认回退。</summary>
- private long ResolveTenantOrThrow()
- {
- var tid = _userManager.TenantId;
- if (tid <= 0)
- throw Oops.Oh("无法确定当前租户,请重新登录或选择目标租户");
- if (_userManager.SuperAdmin && tid == MainTenantId)
- throw Oops.Oh("超级管理员操作前必须选择目标租户");
- return tid;
- }
- /// <summary>
- /// 生产领料单列表(只读分页查询)。
- /// </summary>
- [DisplayName("生产领料单列表")]
- [HttpGet("list")]
- public async Task<object> GetList([FromQuery] ProductionIssueListInput input)
- {
- var page = input.Page <= 0 ? 1 : input.Page;
- var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
- var offset = (page - 1) * pageSize;
- var where = new List<string> { "1=1" };
- var pars = new List<SugarParameter>();
- // 强制租户过滤:租户只来自认证后可信 JWT,忽略前端 input.TenantId,杜绝跨租户可见。
- var tid = ResolveTenantOrThrow();
- where.Add("m.tenant_id = @TenantId");
- pars.Add(new SugarParameter("@TenantId", tid));
- if (!string.IsNullOrWhiteSpace(input.Nbr))
- {
- where.Add("m.nbr LIKE @Nbr");
- pars.Add(new SugarParameter("@Nbr", $"%{input.Nbr.Trim()}%"));
- }
- if (!string.IsNullOrWhiteSpace(input.WorkOrd))
- {
- where.Add("m.work_ord LIKE @WorkOrd");
- pars.Add(new SugarParameter("@WorkOrd", $"%{input.WorkOrd.Trim()}%"));
- }
- if (!string.IsNullOrWhiteSpace(input.Status))
- {
- where.Add("m.status = @Status");
- pars.Add(new SugarParameter("@Status", input.Status.Trim()));
- }
- if (!string.IsNullOrWhiteSpace(input.ProdLine))
- {
- where.Add("m.prod_line LIKE @ProdLine");
- pars.Add(new SugarParameter("@ProdLine", $"%{input.ProdLine.Trim()}%"));
- }
- if (!string.IsNullOrWhiteSpace(input.DateFrom))
- {
- where.Add("m.issue_date >= @DateFrom");
- pars.Add(new SugarParameter("@DateFrom", $"{input.DateFrom.Trim()} 00:00:00"));
- }
- if (!string.IsNullOrWhiteSpace(input.DateTo))
- {
- where.Add("m.issue_date <= @DateTo");
- pars.Add(new SugarParameter("@DateTo", $"{input.DateTo.Trim()} 23:59:59"));
- }
- var whereSql = string.Join(" AND ", where);
- var total = await _db.Ado.GetIntAsync(
- $"SELECT COUNT(1) FROM mdp_std_production_issue m WHERE {whereSql}", pars);
- var list = await _db.Ado.SqlQueryAsync<ProductionIssueListRow>(
- $"""
- SELECT
- m.id AS Id,
- m.nbr AS Nbr,
- m.issue_date AS IssueDate,
- m.status_desc AS StatusDesc,
- m.work_ord AS WorkOrd,
- m.department_desc AS DepartmentDesc,
- m.prod_line AS ProdLine,
- m.qty_ord AS QtyOrd,
- m.issue_user AS IssueUser,
- m.remark AS Remark,
- m.create_user AS CreateUser,
- m.source_create_time AS CreateTime
- FROM mdp_std_production_issue m
- WHERE {whereSql}
- ORDER BY {BuildOrderBy(input.OrderBy, input.OrderDir)}
- LIMIT {pageSize} OFFSET {offset}
- """,
- pars);
- return new { total, page, pageSize, list };
- }
- /// <summary>
- /// 排序白名单:仅允许按已展示列排序,杜绝 SQL 注入;非法字段回落默认。
- /// </summary>
- private static string BuildOrderBy(string? orderBy, string? orderDir)
- {
- var column = orderBy switch
- {
- "nbr" => "m.nbr",
- "issueDate" => "m.issue_date",
- "status" => "m.status",
- "workOrd" => "m.work_ord",
- "prodLine" => "m.prod_line",
- "createTime" => "m.source_create_time",
- _ => "m.issue_date",
- };
- var direction = string.Equals(orderDir, "asc", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
- return $"{column} {direction}, m.id DESC";
- }
- }
|