跳转到主要内容

发货-发货详情(新)

发货详情报表模块(ShipV2)功能解析

1. 模块架构

1.1 前端架构

  • 核心文件wimoor-ui/src/views/amazon/report/shipv2/detail/index.vue
  • 技术栈:Vue 3、Element Plus、Vite、Axios
  • 状态管理:Vue 3 Composition API(reactive、ref)
  • API接口wimoor-ui/src/api/amazon/inbound/reportV2Api.js

1.2 后端架构

  • 控制器ShipInboundReportV2Controller.java
  • 服务层IShipInboundPlanService.javaShipInboundPlanServiceImpl.java
  • 数据访问ShipInboundPlanV2Mapper.javaShipInboundPlanV2Mapper.xml
  • 技术栈:Spring Boot、MyBatis Plus、MySQL

1.3 数据流

前端用户操作 → 筛选条件设置 → API调用 → 后端控制器处理 → 服务层业务逻辑 → Mapper数据查询 → 数据库 → 数据返回 → 前端渲染

2. 前端实现

2.1 核心组件结构

<template>
  <div>
    <!-- 标签页切换 -->
    <el-tabs v-model="selecttype" @tab-change="handleQuery">
      <el-tab-pane label="按货件汇总" name="shipment"></el-tab-pane>
      <el-tab-pane label="按SKU汇总" name="sku"></el-tab-pane>
    </el-tabs>
    
    <!-- 筛选条件 -->
    <div class="filter-bar">
      <!-- 店铺选择 -->
      <el-select v-model="queryParam.groupid" @change="handleQuery">
        <!-- 选项 -->
      </el-select>
      
      <!-- 日期类型选择 -->
      <el-select v-model="queryParam.datetype" @change="handleQuery">
        <el-option label="创建日期" value="createdate"></el-option>
        <el-option label="发货日期" value="senddate"></el-option>
      </el-select>
      
      <!-- 日期范围选择 -->
      <el-date-picker v-model="dateRange" @change="handleQuery"></el-date-picker>
      
      <!-- 仓库选择 -->
      <el-select v-model="queryParam.warehouseid" @change="handleQuery">
        <el-option label="全部" value="all"></el-option>
        <!-- 选项 -->
      </el-select>
      
      <!-- 货件编码搜索 -->
      <el-input v-model="queryParam.search" @keyup.enter="handleQuery"></el-input>
      
      <!-- 高级筛选 -->
      <el-button @click="openFilter">筛选</el-button>
    </div>
    
    <!-- 操作按钮 -->
    <div class="operation-bar">
      <el-button @click="refresh">刷新</el-button>
      <el-button @click="handleExport">导出</el-button>
      <!-- 其他按钮 -->
    </div>
    
    <!-- 数据表格 -->
    <el-table v-loading="isLoading" :data="tableData.records">
      <!-- 列定义 -->
    </el-table>
    
    <!-- 分页 -->
    <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"></el-pagination>
  </div>
</template>

2.2 核心数据结构

2.2.1 响应式状态

const state = reactive({
  selecttype: 'shipment', // 当前选择的视图类型
  dateRange: [], // 日期范围
  queryParam: {
    groupid: undefined, // 店铺ID
    datetype: 'createdate', // 日期类型
    fromdate: '', // 开始日期
    enddate: '', // 结束日期
    warehouseid: 'all', // 仓库ID
    search: '', // 搜索关键词
    hasexceptionnum: '', // 接收异常
    carrierName: '' // 承运商
  },
  tableData: {
    records: [], // 表格数据
    total: 0 // 总记录数
  },
  isLoading: false, // 加载状态
  skutableData: {
    records: [], // SKU表格数据
    total: 0 // SKU总记录数
  },
  sumQty: 0, // 总发货数量
  sumReceivedQty: 0, // 总接收数量
  selectList: [] // 选中的记录
});

2.2.2 API接口

// reportV2Api.js
export default {
  getShipmentReportByLoistics, // 按物流商获取货件报表
  getShipmentReportByWarehouseLoistics, // 按仓库和物流商获取货件报表
  getShipmentDetailReport, // 获取货件详情报表
  getShipmentReport, // 获取货件报表
  downShipmentExcel, // 导出货件Excel
  downExcelShipmentReportByLoistics, // 导出物流商货件报表
  getShipmentReportByWarehouseLoistics
};

2.3 核心方法

2.3.1 数据加载方法

// 加载货件汇总数据
function loadTableData(params) {
  state.isLoading = true;
  reportApi.getShipmentReport(params).then((res) => {
    state.isLoading = false;
    state.tableData.records = res.data.records;
    state.tableData.total = res.data.total;
  });
}

// 加载SKU汇总数据
function skuloadTableData(params) {
  state.isLoading = true;
  reportApi.getShipmentDetailReport(params).then((res) => {
    state.isLoading = false;
    state.skutableData.records = res.data.records;
    state.skutableData.total = res.data.total;
    // 统计总发货和总接收数量
    state.sumQty = res.data.records.reduce((sum, item) => sum + (item.sendqty || 0), 0);
    state.sumReceivedQty = res.data.records.reduce((sum, item) => sum + (item.receivedqty || 0), 0);
  });
}

2.3.2 筛选条件处理

function handleQuery() {
  if (state.selecttype === 'shipment') {
    state.queryParam.pageNum = 1;
    loadTableData(state.queryParam);
  } else {
    state.queryParam.pageNum = 1;
    skuloadTableData(state.queryParam);
  }
}

function handleSizeChange(val) {
  state.queryParam.pageSize = val;
  handleQuery();
}

function handleCurrentChange(val) {
  state.queryParam.pageNum = val;
  handleQuery();
}

2.3.3 导出方法

function downloadList(ftype) {
  if (ftype == "shiptask") {
    // 导出发货处理任务量
    findProcessHandle({"fromdate":state.queryParam.fromdate,"enddate":state.queryParam.enddate});
  } else if (ftype == "shipqty") {
    // 导出发货数量简约版
    inventoryRptApi.downloadOutstockformOut({"fromdate":state.queryParam.fromdate,"enddate":state.queryParam.enddate});
  } else {
    // 其他导出类型
    state.queryParam.downloadType = ftype;
    reportApi.downShipmentExcel(state.queryParam, () => {
      state.downLoading = false;
    });
  }
}

2.4 前端交互逻辑

  1. 视图切换:通过selecttype状态和标签页切换,调用不同的数据加载方法
  2. 筛选条件:所有筛选条件变更都会触发handleQuery方法重新加载数据
  3. 分页:分页操作通过handleSizeChangehandleCurrentChange方法处理
  4. 导出:根据不同的导出类型调用不同的API接口
  5. 数据统计:SKU汇总视图下自动计算总发货和总接收数量

3. 后端实现

3.1 控制器层

3.1.1 核心API接口

API路径 方法 功能
/api/v2/ship/report/getShipmentReport POST 获取货件汇总报表
/api/v2/ship/report/getShipmentDetailReport POST 获取SKU汇总报表
/api/v2/ship/report/downShipmentExcel POST 导出货件报表Excel
/api/v2/ship/report/getShipmentReportByLoistics POST 按物流商获取货件报表
/api/v2/ship/report/getShipmentReportByWarehouseLoistics POST 按仓库和物流商获取货件报表
/api/v2/ship/report/downExcelShipmentReportByLoistics POST 导出物流商货件报表Excel

3.1.2 控制器方法实现

@PostMapping(value = "/getShipmentReport")
public Result<IPage<Map<String, Object>>> getShipmentReport(@RequestBody ShipInboundShipmenSummaryDTO dto) {
    Map<String, Object> param = new HashMap<>();
    // 参数处理
    UserInfo user = UserInfoContext.get();
    param.put("shopid", user.getCompanyid());
    param.put("marketplaceid", dto.getMarketplaceid());
    param.put("groupid", dto.getGroupid());
    param.put("search", dto.getSearch());
    param.put("datetype", dto.getDatetype());
    param.put("fromDate", dto.getFromdate());
    param.put("endDate", dto.getEnddate());
    param.put("warehouseid", dto.getWarehouseid());
    param.put("company", dto.getCompany());
    param.put("companyid", dto.getCompanyid());
    param.put("iserror", dto.getHasexceptionnum());
    
    // 调用服务层
    IPage<Map<String, Object>> pagelist = shipInboundPlanService.getShipmentReport(dto.getPage(), param);
    return Result.success(pagelist);
}

@PostMapping(value = "/downShipmentExcel")
public void downShipmentExcelAction(@RequestBody ShipInboundShipmenSummaryDTO dto, HttpServletResponse response) {
    try {
        // 创建Excel工作簿
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        response.setContentType("application/force-download");
        response.addHeader("Content-Disposition", "attachment;fileName=Shipmenttemplate.xlsx");
        ServletOutputStream fOut = response.getOutputStream();
        
        // 参数处理
        UserInfo user = UserInfoContext.get();
        Map<String, Object> params = new HashMap<>();
        params.put("shopid", user.getCompanyid());
        params.put("datetype", dto.getDatetype());
        params.put("marketplaceid", dto.getMarketplaceid());
        params.put("groupid", dto.getGroupid());
        params.put("search", dto.getSearch());
        params.put("fromDate", dto.getFromdate());
        params.put("endDate", dto.getEnddate());
        params.put("ftype", dto.getDownloadType());
        
        // 调用服务层生成Excel
        shipInboundPlanService.setExcelBookByType(workbook, params);
        
        // 输出Excel
        workbook.write(fOut);
        workbook.close();
        fOut.flush();
        fOut.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

3.2 服务层

3.2.1 服务接口定义

public interface IShipInboundPlanService extends IService<ShipInboundPlan>, IRunAmazonService {
    // 其他方法...
    
    /**
     * 获取货件详情报表
     */
    IPage<Map<String, Object>> getShipmentDetailReport(Page<Object> page, Map<String, Object> param);
    
    /**
     * 获取货件报表
     */
    IPage<Map<String, Object>> getShipmentReport(Page<Object> page, Map<String, Object> param);
    
    /**
     * 按类型设置Excel工作簿
     */
    void setExcelBookByType(SXSSFWorkbook workbook, Map<String, Object> params);
}

3.2.2 服务实现

@Override
public IPage<Map<String, Object>> getShipmentReport(Page<Object> page, Map<String, Object> param) {
    return this.baseMapper.getShipmentReport(page, param);
}

@Override
public IPage<Map<String, Object>> getShipmentDetailReport(Page<Object> page, Map<String, Object> param) {
    return this.baseMapper.getShipmentDetailReport(page, param);
}

@Override
public void setExcelBookByType(SXSSFWorkbook workbook, Map<String, Object> params) {
    String type = params.get("ftype").toString();
    if ("shipment".equals(type)) {
        // 货件汇总导出
        Map<String, Object> titlemap = new LinkedHashMap<>();
        titlemap.put("ShipmentId", "货件编码");
        titlemap.put("groupname", "发货店铺");
        titlemap.put("warehousename", "发货仓库");
        // 更多列定义...
        
        List<Map<String, Object>> list = this.baseMapper.getShipmentReport(params);
        Sheet sheet = workbook.createSheet("sheet1");
        // 写入表头和数据
    } else if ("sku".equals(type)) {
        // SKU汇总导出
        // 类似实现...
    }
}

3.3 数据访问层

3.3.1 Mapper接口

public interface ShipInboundPlanV2Mapper extends BaseMapper<ShipInboundPlan> {
    // 其他方法...
    
    /**
     * 获取货件报表
     */
    IPage<Map<String, Object>> getShipmentReport(Page<Object> page, @Param("param") Map<String, Object> param);
    
    /**
     * 获取货件详情报表
     */
    IPage<Map<String, Object>> getShipmentDetailReport(Page<Object> page, @Param("param") Map<String, Object> param);
    
    /**
     * 获取货件报表(导出用)
     */
    List<Map<String, Object>> getShipmentReport(@Param("param") Map<String, Object> param);
    
    /**
     * 获取货件详情报表(导出用)
     */
    List<Map<String, Object>> getShipmentDetailReport(@Param("param") Map<String, Object> param);
}

3.3.2 SQL实现

getShipmentReport(货件汇总)

<select id="getShipmentReport" parameterType="java.util.Map" resultType="java.util.Map">
    SELECT
        s.ShipmentId,
        ag.name AS groupname,
        wh.name AS warehousename,
        s.createdate,
        s.senddate,
        s.receivedate,
        s.completedate,
        s.destination,
        s.marketplace,
        s.warehouseid,
        s.estimateddeliverydate,
        s.carrierName,
        s.shippingchannel,
        SUM(i.receivedqty) AS receivedqty,
        SUM(i.quantity) AS sendqty,
        SUM(s.fee) AS feecount,
        s.weight,
        s.weightfee,
        s.otherfee,
        s.actualweight,
        s.estimateweight,
        s.boxactualweight,
        s.boxvolumeweight
    FROM
        t_erp_ship_v2_inboundplan s
    LEFT JOIN
        t_amazon_group ag ON ag.id = s.groupid
    LEFT JOIN
        t_erp_warehouse wh ON wh.id = s.warehouseid
    LEFT JOIN
        t_erp_ship_v2_inbounditem i ON i.formid = s.id
    WHERE
        s.shopid = #{param.shopid}
        <if test="param.marketplaceid != null">
            AND s.marketplaceid = #{param.marketplaceid}
        </if>
        <if test="param.groupid != null">
            AND s.groupid = #{param.groupid}
        </if>
        <if test="param.search != null">
            AND s.ShipmentId LIKE #{param.search}
        </if>
        <!-- 更多条件... -->
    GROUP BY
        s.ShipmentId
    ORDER BY
        s.createdate DESC
</select>

getShipmentDetailReport(SKU汇总)

<select id="getShipmentDetailReport" parameterType="java.util.Map" resultType="java.util.Map">
    SELECT
        i.sku,
        s.ShipmentId,
        s.number,
        ag.name AS groupname,
        s.destination,
        s.warehouseid,
        wh.name AS warehousename,
        s.senddate,
        s.receivedate,
        s.shippingchannel,
        s.estimateddeliverydate,
        i.quantity AS sendqty,
        i.receivedqty,
        s.status,
        s.createdate
    FROM
        t_erp_ship_v2_inboundplan s
    LEFT JOIN
        t_amazon_group ag ON ag.id = s.groupid
    LEFT JOIN
        t_erp_warehouse wh ON wh.id = s.warehouseid
    LEFT JOIN
        t_erp_ship_v2_inbounditem i ON i.formid = s.id
    WHERE
        s.shopid = #{param.shopid}
        <if test="param.marketplaceid != null">
            AND s.marketplaceid = #{param.marketplaceid}
        </if>
        <if test="param.groupid != null">
            AND s.groupid = #{param.groupid}
        </if>
        <if test="param.search != null">
            AND (s.ShipmentId LIKE #{param.search} OR i.sku LIKE #{param.search})
        </if>
        <!-- 更多条件... -->
    ORDER BY
        s.createdate DESC
</select>

4. 功能特性

4.1 双视图模式

  • 货件汇总视图:以货件为单位,展示货件的整体情况
  • SKU汇总视图:以SKU为单位,展示每个SKU的发货和到货情况

4.2 多维度筛选

筛选条件 说明 数据类型
店铺 选择特定店铺 下拉选择
日期类型 创建日期/发货日期 下拉选择
日期范围 选择开始和结束日期 日期选择器
仓库 选择特定仓库 下拉选择
货件编码 搜索特定货件 文本输入
接收异常 筛选有/无接收异常的货件 下拉选择
承运商 选择特定承运商 下拉选择

4.3 数据导出

导出类型 说明 适用场景
普通导出 完整的货件或SKU数据 全面分析
含子SKU 包含子SKU的详细数据 变体产品分析
发货数量简约版 只包含发货数量的简化数据 快速统计
发货处理任务量 发货处理任务量统计 任务分配

4.4 数据统计

  • SKU汇总视图:自动计算总发货数量和总接收数量
  • 货件汇总视图:自动汇总物流费用、运输重量等

5. 技术亮点

5.1 前端技术亮点

  1. Vue 3 Composition API:使用reactive和ref进行状态管理,代码结构更清晰
  2. Element Plus组件:使用el-tabs、el-select、el-table等组件,界面美观且功能丰富
  3. 响应式设计:适配不同屏幕尺寸,操作流畅
  4. 异步数据加载:使用Axios进行异步请求,配合loading状态提升用户体验
  5. 条件渲染:根据不同视图类型和筛选条件动态渲染UI

5.2 后端技术亮点

  1. RESTful API设计:使用POST请求传递复杂参数,接口设计规范
  2. SXSSFWorkbook:使用SXSSFWorkbook处理大数据量Excel导出,避免内存溢出
  3. 参数校验:对输入参数进行非空检查和格式转换
  4. 多表关联查询:使用SQL多表关联查询,提高数据查询效率
  5. 动态SQL:使用MyBatis Plus的动态SQL,根据条件构建不同的查询语句

5.3 性能优化

  1. 分页查询:使用MyBatis Plus的分页功能,避免一次性加载过多数据
  2. 索引优化:数据库表建立适当索引,提高查询速度
  3. 缓存机制:使用Spring Cache缓存常用数据
  4. 批量操作:批量处理数据,减少数据库交互次数
  5. 异步处理:Excel导出等耗时操作使用异步处理

6. 代码优化建议

6.1 前端优化建议

  1. 代码模块化:将筛选条件、表格渲染等功能拆分为独立组件
  2. 状态管理:考虑使用Pinia或Vuex进行更复杂的状态管理
  3. 防抖处理:对搜索输入添加防抖处理,减少频繁请求
  4. 虚拟滚动:对大数据量表格使用虚拟滚动,提高渲染性能
  5. 错误处理:添加更完善的错误处理和用户提示

6.2 后端优化建议

  1. 参数验证:使用Spring Validation对请求参数进行更严格的验证
  2. 异常处理:统一异常处理,返回更友好的错误信息
  3. 日志记录:添加更详细的日志记录,便于问题排查
  4. 性能监控:集成Spring Boot Actuator进行性能监控
  5. SQL优化:进一步优化SQL查询,减少表关联次数

6.3 架构优化建议

  1. 微服务拆分:考虑将报表功能拆分为独立的微服务
  2. 缓存策略:使用Redis缓存热点数据,提高响应速度
  3. 消息队列:使用消息队列处理异步任务,提高系统可靠性
  4. API网关:使用API网关统一管理API接口
  5. 容器化部署:使用Docker容器化部署,提高部署效率

7. 业务价值

7.1 运营价值

  1. 数据可视化:通过报表直观展示发货数据,便于运营分析
  2. 异常监控:及时发现和处理接收异常,减少损失
  3. 趋势分析:分析发货趋势,优化库存管理
  4. 成本控制:监控物流费用,优化物流方案

7.2 管理价值

  1. 决策支持:基于数据做出更合理的发货决策
  2. 流程优化:发现发货流程中的瓶颈,优化流程
  3. 绩效考核:基于发货数据进行绩效考核
  4. 风险控制:及时发现和应对发货风险

7.3 技术价值

  1. 可扩展性:模块化设计,便于后续功能扩展
  2. 可维护性:代码结构清晰,易于维护
  3. 可复用性:封装通用功能,提高代码复用率
  4. 技术栈更新:使用Vue 3、Spring Boot等最新技术,保持技术先进性

8. 总结

发货详情报表模块(ShipV2)是一个功能完善、技术先进的FBA发货数据分析工具,通过前端Vue 3和后端Spring Boot的完美结合,实现了货件和SKU两个维度的数据分析和管理。该模块不仅提供了丰富的筛选和导出功能,还通过多表关联查询和数据统计,为用户提供了全面、准确的发货数据,帮助用户更好地管理FBA发货流程,优化物流方案,降低运营成本。

未来,该模块可以进一步扩展,例如添加更多的数据分析维度、集成更多的物流商数据、提供更丰富的图表展示等,以满足用户日益增长的需求。