Files
2026-06-01 16:30:29 +08:00

23 KiB
Raw Permalink Blame History

到货交接单和出货交接单模块规格说明

1. 需求概述

在系统中增加两个新模块:到货交接单和出货交接单,用于记录和管理货物的交接过程。

1.1 到货交接单

  • 交接单号:唯一标识
  • 头程物流商送达时间:物流商送达时间
  • 收货时间:实际收货时间
  • POD:图片链接,多张用逗号隔开
  • 备注:交接备注信息
  • 创建人:创建该交接单的用户
  • 创建时间:交接单创建时间
  • 修改时间:交接单最后修改时间

1.2 出货交接单

  • 交接单号:唯一标识,格式如 BOL-GOFO-202
  • 大包数:大包数量
  • 小包数:小包数量
  • 渠道:物流渠道
  • 交货时间:实际交货时间
  • POD:图片链接,多张用逗号隔开
  • 备注:交接备注信息
  • 创建人:创建该交接单的用户
  • 创建时间:交接单创建时间
  • 修改时间:交接单最后修改时间

2. 技术方案

2.1 数据库设计

2.1.1 到货交接单表 (arrival_handover_forms)

字段名 数据类型 约束 描述
Id INT PRIMARY KEY, AUTO_INCREMENT 主键ID
HandoverNumber VARCHAR(100) NOT NULL, UNIQUE 交接单号
LogisticsProviderArrivalTime DATETIME NULL 头程物流商送达时间
ReceiptTime DATETIME NULL 收货时间
POD TEXT NULL 图片链接,多张用逗号隔开
Remarks TEXT NULL 备注
Creator VARCHAR(50) NOT NULL 创建人
CreatedAt DATETIME NOT NULL 创建时间
UpdatedAt DATETIME NOT NULL 修改时间

2.1.2 出货交接单表 (shipping_handover_forms)

字段名 数据类型 约束 描述
Id INT PRIMARY KEY, AUTO_INCREMENT 主键ID
HandoverNumber VARCHAR(100) NOT NULL, UNIQUE 交接单号
BigBagCount INT NOT NULL 大包数
SmallBagCount INT NOT NULL 小包数
Channel VARCHAR(100) NOT NULL 渠道
DeliveryTime DATETIME NULL 交货时间
POD TEXT NULL 图片链接,多张用逗号隔开
Remarks TEXT NULL 备注
Creator VARCHAR(50) NOT NULL 创建人
CreatedAt DATETIME NOT NULL 创建时间
UpdatedAt DATETIME NOT NULL 修改时间

2.2 模型设计

2.2.1 到货交接单模型 (ArrivalHandoverFormEntity)

using System;
using SqlSugar;

namespace MDL.Models
{
    [SugarTable("arrival_handover_forms")]
    public class ArrivalHandoverFormEntity
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }

        [SugarColumn(Length = 100, IsNullable = false, IsUnique = true)]
        public string HandoverNumber { get; set; }

        [SugarColumn(IsNullable = true)]
        public DateTime? LogisticsProviderArrivalTime { get; set; }

        [SugarColumn(IsNullable = true)]
        public DateTime? ReceiptTime { get; set; }

        [SugarColumn(ColumnDataType = "TEXT", IsNullable = true)]
        public string POD { get; set; }

        [SugarColumn(ColumnDataType = "TEXT", IsNullable = true)]
        public string Remarks { get; set; }

        [SugarColumn(Length = 50, IsNullable = false)]
        public string Creator { get; set; }

        [SugarColumn(IsNullable = false)]
        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

        [SugarColumn(IsNullable = false)]
        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    }
}

2.2.2 出货交接单模型 (ShippingHandoverFormEntity)

using System;
using SqlSugar;

namespace MDL.Models
{
    [SugarTable("shipping_handover_forms")]
    public class ShippingHandoverFormEntity
    {
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }

        [SugarColumn(Length = 100, IsNullable = false, IsUnique = true)]
        public string HandoverNumber { get; set; }

        [SugarColumn(IsNullable = false)]
        public int BigBagCount { get; set; }

        [SugarColumn(IsNullable = false)]
        public int SmallBagCount { get; set; }

        [SugarColumn(Length = 100, IsNullable = false)]
        public string Channel { get; set; }

        [SugarColumn(IsNullable = true)]
        public DateTime? DeliveryTime { get; set; }

        [SugarColumn(ColumnDataType = "TEXT", IsNullable = true)]
        public string POD { get; set; }

        [SugarColumn(ColumnDataType = "TEXT", IsNullable = true)]
        public string Remarks { get; set; }

        [SugarColumn(Length = 50, IsNullable = false)]
        public string Creator { get; set; }

        [SugarColumn(IsNullable = false)]
        public DateTime CreatedAt { get; set; } = DateTime.UtcNow;

        [SugarColumn(IsNullable = false)]
        public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
    }
}

2.3 仓库设计

2.3.1 到货交接单仓库接口 (IArrivalHandoverFormRepository)

using System.Collections.Generic;
using System.Threading.Tasks;
using MDL.Models;

namespace DAL.Interfaces
{
    public interface IArrivalHandoverFormRepository
    {
        Task<int> InsertAsync(ArrivalHandoverFormEntity form);
        Task<ArrivalHandoverFormEntity> GetByIdAsync(int id);
        Task<ArrivalHandoverFormEntity> GetByHandoverNumberAsync(string handoverNumber);
        Task<List<ArrivalHandoverFormEntity>> GetAllAsync();
        Task<int> UpdateAsync(ArrivalHandoverFormEntity form);
        Task<int> DeleteAsync(int id);
        Task<bool> ExistsByHandoverNumberAsync(string handoverNumber);
        Task<(List<ArrivalHandoverFormEntity> Forms, int TotalCount)> GetArrivalHandoverFormsBatchAsync(
            int page, 
            int pageSize, 
            string sortBy, 
            string sortOrder,
            string handoverNumber,
            string creator);
    }
}

2.3.2 出货交接单仓库接口 (IShippingHandoverFormRepository)

using System.Collections.Generic;
using System.Threading.Tasks;
using MDL.Models;

namespace DAL.Interfaces
{
    public interface IShippingHandoverFormRepository
    {
        Task<int> InsertAsync(ShippingHandoverFormEntity form);
        Task<ShippingHandoverFormEntity> GetByIdAsync(int id);
        Task<ShippingHandoverFormEntity> GetByHandoverNumberAsync(string handoverNumber);
        Task<List<ShippingHandoverFormEntity>> GetAllAsync();
        Task<int> UpdateAsync(ShippingHandoverFormEntity form);
        Task<int> DeleteAsync(int id);
        Task<bool> ExistsByHandoverNumberAsync(string handoverNumber);
        Task<(List<ShippingHandoverFormEntity> Forms, int TotalCount)> GetShippingHandoverFormsBatchAsync(
            int page, 
            int pageSize, 
            string sortBy, 
            string sortOrder,
            string handoverNumber,
            string channel,
            string creator);
    }
}

2.4 服务设计

2.4.1 到货交接单服务接口 (IArrivalHandoverFormService)

using System.Collections.Generic;
using System.Threading.Tasks;
using MDL.Models;

namespace BLL.Interfaces
{
    public interface IArrivalHandoverFormService
    {
        Task<int> CreateArrivalHandoverFormAsync(ArrivalHandoverFormEntity form);
        Task<ArrivalHandoverFormEntity> GetArrivalHandoverFormByIdAsync(int id);
        Task<ArrivalHandoverFormEntity> GetArrivalHandoverFormByNumberAsync(string handoverNumber);
        Task<List<ArrivalHandoverFormEntity>> GetAllArrivalHandoverFormsAsync();
        Task<int> UpdateArrivalHandoverFormAsync(ArrivalHandoverFormEntity form);
        Task<int> DeleteArrivalHandoverFormAsync(int id);
        Task<string> GenerateArrivalHandoverNumberAsync();
        Task<(List<ArrivalHandoverFormEntity> Forms, int TotalCount)> GetArrivalHandoverFormsBatchAsync(
            int page, 
            int pageSize, 
            string sortBy, 
            string sortOrder,
            string handoverNumber,
            string creator);
    }
}

2.4.2 出货交接单服务接口 (IShippingHandoverFormService)

using System.Collections.Generic;
using System.Threading.Tasks;
using MDL.Models;

namespace BLL.Interfaces
{
    public interface IShippingHandoverFormService
    {
        Task<int> CreateShippingHandoverFormAsync(ShippingHandoverFormEntity form);
        Task<ShippingHandoverFormEntity> GetShippingHandoverFormByIdAsync(int id);
        Task<ShippingHandoverFormEntity> GetShippingHandoverFormByNumberAsync(string handoverNumber);
        Task<List<ShippingHandoverFormEntity>> GetAllShippingHandoverFormsAsync();
        Task<int> UpdateShippingHandoverFormAsync(ShippingHandoverFormEntity form);
        Task<int> DeleteShippingHandoverFormAsync(int id);
        Task<string> GenerateShippingHandoverNumberAsync();
        Task<(List<ShippingHandoverFormEntity> Forms, int TotalCount)> GetShippingHandoverFormsBatchAsync(
            int page, 
            int pageSize, 
            string sortBy, 
            string sortOrder,
            string handoverNumber,
            string channel,
            string creator);
    }
}

2.5 控制器设计

2.5.1 到货交接单控制器 (ArrivalHandoverFormController)

using BLL.Interfaces;
using MDL.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;

namespace CONTROLLER.Controllers
{
    [Route("api/arrival-handover")]
    [ApiController]
    public class ArrivalHandoverFormController : ControllerBase
    {
        private readonly IArrivalHandoverFormService _arrivalHandoverFormService;

        public ArrivalHandoverFormController(IArrivalHandoverFormService arrivalHandoverFormService)
        {
            _arrivalHandoverFormService = arrivalHandoverFormService;
        }

        [HttpPost("create")]
        public async Task<IActionResult> CreateArrivalHandoverForm([FromBody] ArrivalHandoverFormEntity form)
        {
            try
            {
                if (string.IsNullOrEmpty(form.HandoverNumber))
                {
                    form.HandoverNumber = await _arrivalHandoverFormService.GenerateArrivalHandoverNumberAsync();
                }
                form.CreatedAt = DateTime.UtcNow;
                form.UpdatedAt = DateTime.UtcNow;
                var result = await _arrivalHandoverFormService.CreateArrivalHandoverFormAsync(form);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = result
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpGet("get/{id}")]
        public async Task<IActionResult> GetArrivalHandoverFormById(int id)
        {
            try
            {
                var form = await _arrivalHandoverFormService.GetArrivalHandoverFormByIdAsync(id);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = form
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpGet("get-by-number/{handoverNumber}")]
        public async Task<IActionResult> GetArrivalHandoverFormByNumber(string handoverNumber)
        {
            try
            {
                var form = await _arrivalHandoverFormService.GetArrivalHandoverFormByNumberAsync(handoverNumber);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = form
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpGet("list")]
        public async Task<IActionResult> GetArrivalHandoverForms(
            [FromQuery] int page = 1,
            [FromQuery] int pageSize = 10,
            [FromQuery] string sortBy = "CreatedAt",
            [FromQuery] string sortOrder = "desc",
            [FromQuery] string handoverNumber = "",
            [FromQuery] string creator = "")
        {
            try
            {
                var (forms, totalCount) = await _arrivalHandoverFormService.GetArrivalHandoverFormsBatchAsync(
                    page, pageSize, sortBy, sortOrder, handoverNumber, creator);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = new
                    {
                        forms,
                        totalCount
                    }
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpPut("update")]
        public async Task<IActionResult> UpdateArrivalHandoverForm([FromBody] ArrivalHandoverFormEntity form)
        {
            try
            {
                form.UpdatedAt = DateTime.UtcNow;
                var result = await _arrivalHandoverFormService.UpdateArrivalHandoverFormAsync(form);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = result
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpDelete("delete/{id}")]
        public async Task<IActionResult> DeleteArrivalHandoverForm(int id)
        {
            try
            {
                var result = await _arrivalHandoverFormService.DeleteArrivalHandoverFormAsync(id);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = result
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpGet("generate-number")]
        public async Task<IActionResult> GenerateArrivalHandoverNumber()
        {
            try
            {
                var number = await _arrivalHandoverFormService.GenerateArrivalHandoverNumberAsync();
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = number
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }
    }
}

2.5.2 出货交接单控制器 (ShippingHandoverFormController)

using BLL.Interfaces;
using MDL.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;

namespace CONTROLLER.Controllers
{
    [Route("api/shipping-handover")]
    [ApiController]
    public class ShippingHandoverFormController : ControllerBase
    {
        private readonly IShippingHandoverFormService _shippingHandoverFormService;

        public ShippingHandoverFormController(IShippingHandoverFormService shippingHandoverFormService)
        {
            _shippingHandoverFormService = shippingHandoverFormService;
        }

        [HttpPost("create")]
        public async Task<IActionResult> CreateShippingHandoverForm([FromBody] ShippingHandoverFormEntity form)
        {
            try
            {
                if (string.IsNullOrEmpty(form.HandoverNumber))
                {
                    form.HandoverNumber = await _shippingHandoverFormService.GenerateShippingHandoverNumberAsync();
                }
                form.CreatedAt = DateTime.UtcNow;
                form.UpdatedAt = DateTime.UtcNow;
                var result = await _shippingHandoverFormService.CreateShippingHandoverFormAsync(form);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = result
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpGet("get/{id}")]
        public async Task<IActionResult> GetShippingHandoverFormById(int id)
        {
            try
            {
                var form = await _shippingHandoverFormService.GetShippingHandoverFormByIdAsync(id);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = form
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpGet("get-by-number/{handoverNumber}")]
        public async Task<IActionResult> GetShippingHandoverFormByNumber(string handoverNumber)
        {
            try
            {
                var form = await _shippingHandoverFormService.GetShippingHandoverFormByNumberAsync(handoverNumber);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = form
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpGet("list")]
        public async Task<IActionResult> GetShippingHandoverForms(
            [FromQuery] int page = 1,
            [FromQuery] int pageSize = 10,
            [FromQuery] string sortBy = "CreatedAt",
            [FromQuery] string sortOrder = "desc",
            [FromQuery] string handoverNumber = "",
            [FromQuery] string channel = "",
            [FromQuery] string creator = "")
        {
            try
            {
                var (forms, totalCount) = await _shippingHandoverFormService.GetShippingHandoverFormsBatchAsync(
                    page, pageSize, sortBy, sortOrder, handoverNumber, channel, creator);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = new
                    {
                        forms,
                        totalCount
                    }
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpPut("update")]
        public async Task<IActionResult> UpdateShippingHandoverForm([FromBody] ShippingHandoverFormEntity form)
        {
            try
            {
                form.UpdatedAt = DateTime.UtcNow;
                var result = await _shippingHandoverFormService.UpdateShippingHandoverFormAsync(form);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = result
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpDelete("delete/{id}")]
        public async Task<IActionResult> DeleteShippingHandoverForm(int id)
        {
            try
            {
                var result = await _shippingHandoverFormService.DeleteShippingHandoverFormAsync(id);
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = result
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }

        [HttpGet("generate-number")]
        public async Task<IActionResult> GenerateShippingHandoverNumber()
        {
            try
            {
                var number = await _shippingHandoverFormService.GenerateShippingHandoverNumberAsync();
                return Ok(new
                {
                    code = 0,
                    message = "success",
                    data = number
                });
            }
            catch (Exception ex)
            {
                return Ok(new
                {
                    code = 9999,
                    message = ex.Message
                });
            }
        }
    }
}

3. 数据库SQL脚本

3.1 到货交接单表创建脚本

CREATE TABLE IF NOT EXISTS `arrival_handover_forms` (
  `Id` INT NOT NULL AUTO_INCREMENT,
  `HandoverNumber` VARCHAR(100) NOT NULL,
  `LogisticsProviderArrivalTime` DATETIME NULL,
  `ReceiptTime` DATETIME NULL,
  `POD` TEXT NULL,
  `Remarks` TEXT NULL,
  `Creator` VARCHAR(50) NOT NULL,
  `CreatedAt` DATETIME NOT NULL,
  `UpdatedAt` DATETIME NOT NULL,
  PRIMARY KEY (`Id`),
  UNIQUE INDEX `UQ_HandoverNumber` (`HandoverNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

3.2 出货交接单表创建脚本

CREATE TABLE IF NOT EXISTS `shipping_handover_forms` (
  `Id` INT NOT NULL AUTO_INCREMENT,
  `HandoverNumber` VARCHAR(100) NOT NULL,
  `BigBagCount` INT NOT NULL,
  `SmallBagCount` INT NOT NULL,
  `Channel` VARCHAR(100) NOT NULL,
  `DeliveryTime` DATETIME NULL,
  `POD` TEXT NULL,
  `Remarks` TEXT NULL,
  `Creator` VARCHAR(50) NOT NULL,
  `CreatedAt` DATETIME NOT NULL,
  `UpdatedAt` DATETIME NOT NULL,
  PRIMARY KEY (`Id`),
  UNIQUE INDEX `UQ_HandoverNumber` (`HandoverNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

4. 实现计划

  1. 创建模型类在MDL项目中创建ArrivalHandoverFormEntity和ShippingHandoverFormEntity
  2. 创建仓库接口在DAL项目中创建IArrivalHandoverFormRepository和IShippingHandoverFormRepository
  3. 实现仓库类在DAL项目中实现ArrivalHandoverFormRepository和ShippingHandoverFormRepository
  4. 创建服务接口在BLL项目中创建IArrivalHandoverFormService和IShippingHandoverFormService
  5. 实现服务类在BLL项目中实现ArrivalHandoverFormService和ShippingHandoverFormService
  6. 创建控制器在CONTROLLER项目中创建ArrivalHandoverFormController和ShippingHandoverFormController
  7. 更新依赖注入在Program.cs中注册新的服务和仓库
  8. 测试API验证所有CRUD操作是否正常工作

5. 验收标准

  1. 数据库表结构正确创建
  2. 所有API接口正常工作
  3. 交接单号生成规则正确
  4. POD字段支持多个图片链接用逗号隔开
  5. 分页查询功能正常
  6. 所有CRUD操作返回正确的响应格式