workbench-current-state.png
yudao-module-mdm/src/main/java/cn/iocoder/yudao/module/mdm/controller/admin/unit/MdmUnitMeasureController.java
@@ -46,14 +46,14 @@ @PostMapping("/create") @Operation(summary = "创建计量单位") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:create')") @PreAuthorize("@ss.hasPermission('mdm:unit:create')") public CommonResult<Long> createUnitMeasure(@Valid @RequestBody MdmUnitMeasureSaveReqVO createReqVO) { return success(unitMeasureService.createUnitMeasure(createReqVO)); } @PutMapping("/update") @Operation(summary = "更新计量单位") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:update')") @PreAuthorize("@ss.hasPermission('mdm:unit:update')") public CommonResult<Boolean> updateUnitMeasure(@Valid @RequestBody MdmUnitMeasureSaveReqVO updateReqVO) { unitMeasureService.updateUnitMeasure(updateReqVO); return success(true); @@ -63,7 +63,7 @@ @Operation(summary = "更新计量单位状态") @Parameter(name = "id", description = "编号", required = true, example = "1") @Parameter(name = "status", description = "状态", required = true, example = "0") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:update')") @PreAuthorize("@ss.hasPermission('mdm:unit:update')") public CommonResult<Boolean> updateUnitMeasureStatus(@RequestParam("id") Long id, @RequestParam("status") Integer status) { unitMeasureService.updateUnitMeasureStatus(id, status); return success(true); @@ -72,7 +72,7 @@ @DeleteMapping("/delete") @Operation(summary = "删除计量单位") @Parameter(name = "id", description = "编号", required = true, example = "1") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:delete')") @PreAuthorize("@ss.hasPermission('mdm:unit:delete')") public CommonResult<Boolean> deleteUnitMeasure(@RequestParam("id") Long id) { unitMeasureService.deleteUnitMeasure(id); return success(true); @@ -81,21 +81,21 @@ @GetMapping("/get") @Operation(summary = "获得计量单位") @Parameter(name = "id", description = "编号", required = true, example = "1") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')") @PreAuthorize("@ss.hasPermission('mdm:unit:query')") public CommonResult<MdmUnitMeasureDO> getUnitMeasure(@RequestParam("id") Long id) { return success(unitMeasureService.getUnitMeasure(id)); } @GetMapping("/page") @Operation(summary = "获得计量单位分页") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')") @PreAuthorize("@ss.hasPermission('mdm:unit:query')") public CommonResult<PageResult<MdmUnitMeasureDO>> getUnitMeasurePage(@Valid MdmUnitMeasurePageReqVO pageReqVO) { return success(unitMeasureService.getUnitMeasurePage(pageReqVO)); } @GetMapping("/list") @Operation(summary = "获得计量单位列表") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')") @PreAuthorize("@ss.hasPermission('mdm:unit:query')") public CommonResult<List<MdmUnitMeasureDO>> getUnitMeasureList() { return success(unitMeasureService.getUnitMeasureList(null)); } @@ -103,14 +103,14 @@ @GetMapping("/list-by-ids") @Operation(summary = "获得计量单位列表") @Parameter(name = "ids", description = "编号列表", required = true, example = "1,2,3") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:query')") @PreAuthorize("@ss.hasPermission('mdm:unit:query')") public CommonResult<List<MdmUnitMeasureDO>> getUnitMeasureListByIds(@RequestParam("ids") List<Long> ids) { return success(unitMeasureService.getUnitMeasureList(ids)); } @GetMapping("/export-excel") @Operation(summary = "导出计量单位 Excel") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:export')") @PreAuthorize("@ss.hasPermission('mdm:unit:export')") @ApiAccessLog(operateType = EXPORT) public void exportUnitMeasureExcel(@Valid MdmUnitMeasurePageReqVO pageReqVO, HttpServletResponse response) throws IOException { @@ -138,7 +138,7 @@ @GetMapping("/get-import-template") @Operation(summary = "获得导入计量单位模板") @PreAuthorize("@ss.hasPermission('mdm:unit-measure:import')") @PreAuthorize("@ss.hasPermission('mdm:unit:import')") public void importTemplate(HttpServletResponse response) throws IOException { List<MdmUnitMeasureImportExcelVO> list = Arrays.asList( MdmUnitMeasureImportExcelVO.builder().code("PC").name("片").primaryFlag(true).changeRate(new java.math.BigDecimal("1")).status(0).remark("示例:主单位").build(), @@ -153,7 +153,7 @@ @Parameter(name = "file", description = "Excel 文件", required = true), @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true") }) @PreAuthorize("@ss.hasPermission('mdm:unit-measure:import')") @PreAuthorize("@ss.hasPermission('mdm:unit:import')") public CommonResult<MdmUnitMeasureImportRespVO> importExcel(@RequestParam("file") MultipartFile file, @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception { List<MdmUnitMeasureImportExcelVO> list = ExcelUtils.read(file, MdmUnitMeasureImportExcelVO.class); yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/route/vo/process/MesProRouteProcessSaveReqVO.java
@@ -17,15 +17,13 @@ @NotNull(message = "工艺路线编号不能为空") private Long routeId; @Schema(description = "工序编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "工序编号不能为空") @Schema(description = "工序编号", example = "1") private Long processId; @Schema(description = "工艺参数模板编号", example = "1") private Long paramTemplateId; @Schema(description = "序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @NotNull(message = "序号不能为空") @Schema(description = "序号", example = "1") private Integer sort; @Schema(description = "与下一道工序关系", example = "0") yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/pro/workorder/MesProWorkOrderBomController.java
@@ -245,7 +245,9 @@ } List<MesProWorkOrderBomDO> items = new ArrayList<>(); for (MesProWorkOrderBomDO bom : bomList) { if (bom.getProcessId().equals(process.getProcessId())) { // 跳过无工序编号的投料行(工单 BOM 中仅按工序维护投料明细,无工序的行不参与展开, // 且 getProcessId 可能为 null,直接 equals 会 NPE) if (Objects.equals(bom.getProcessId(), process.getProcessId())) { items.add(bom); } } @@ -263,7 +265,7 @@ // 3. 以最后一道工序的投料为起点 Map<Long, BigDecimal> currentLayer = new LinkedHashMap<>(); for (MesProWorkOrderBomDO bom : bomList) { if (bom.getProcessId().equals(lastProcess.getProcessId())) { if (Objects.equals(bom.getProcessId(), lastProcess.getProcessId())) { currentLayer.merge(bom.getItemId(), bom.getQuantity(), BigDecimal::add); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/ipqc/vo/MesQcIpqcRespVO.java
@@ -2,6 +2,9 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated; import cn.idev.excel.annotation.ExcelProperty; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.module.mes.enums.DictTypeConstants; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -26,7 +29,8 @@ private String name; @Schema(description = "IPQC 检验类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @ExcelProperty("检验类型") @ExcelProperty(value = "检验类型", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_IPQC_TYPE) private Integer type; @Schema(description = "检验模板 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") @@ -89,9 +93,11 @@ private String itemName; @Schema(description = "规格型号", example = "100mm*50mm") @ExcelProperty("规格型号") private String itemSpecification; @Schema(description = "单位名称", example = "个") @ExcelProperty("单位") private String unitName; // ========== 数量 ========== @@ -143,7 +149,8 @@ // ========== 检验 ========== @Schema(description = "检测结果", example = "1") @ExcelProperty("检测结果") @ExcelProperty(value = "检测结果", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_QC_CHECK_RESULT) private Integer checkResult; @Schema(description = "检测日期") @@ -158,7 +165,8 @@ private String inspectorNickname; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @ExcelProperty("状态") @ExcelProperty(value = "状态", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_ORDER_STATUS) private Integer status; @Schema(description = "备注", example = "备注") yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcRespVO.java
@@ -2,6 +2,9 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated; import cn.idev.excel.annotation.ExcelProperty; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.module.mes.enums.DictTypeConstants; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -48,6 +51,7 @@ private Long vendorId; @Schema(description = "供应商简称", example = "供应商A") @ExcelProperty("供应商简称") private String vendorNickname; @Schema(description = "供应商批次号", example = "VB20250101") @@ -114,7 +118,8 @@ // ========== 检验 ========== @Schema(description = "检测结果", example = "1") @ExcelProperty("检测结果") @ExcelProperty(value = "检测结果", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_QC_CHECK_RESULT) private Integer checkResult; @Schema(description = "来料日期") @@ -133,7 +138,8 @@ private String inspectorNickname; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @ExcelProperty("状态") @ExcelProperty(value = "状态", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_ORDER_STATUS) private Integer status; @Schema(description = "备注", example = "备注") yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/oqc/vo/MesQcOqcRespVO.java
@@ -2,6 +2,9 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated; import cn.idev.excel.annotation.ExcelProperty; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.module.mes.enums.DictTypeConstants; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -69,9 +72,11 @@ private String itemName; @Schema(description = "规格型号", example = "100mm*50mm") @ExcelProperty("规格型号") private String itemSpecification; @Schema(description = "单位名称", example = "个") @ExcelProperty("单位") private String unitName; // ========== 数量 ========== @@ -121,7 +126,8 @@ // ========== 检验 ========== @Schema(description = "检测结果", example = "1") @ExcelProperty("检测结果") @ExcelProperty(value = "检测结果", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_QC_CHECK_RESULT) private Integer checkResult; @Schema(description = "出货日期") @@ -140,7 +146,8 @@ private String inspectorNickname; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @ExcelProperty("状态") @ExcelProperty(value = "状态", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_ORDER_STATUS) private Integer status; @Schema(description = "备注", example = "备注") yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java
@@ -2,6 +2,9 @@ import cn.idev.excel.annotation.ExcelIgnoreUnannotated; import cn.idev.excel.annotation.ExcelProperty; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; import cn.iocoder.yudao.module.mes.enums.DictTypeConstants; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -31,6 +34,8 @@ // ========== 来源单据 ========== @Schema(description = "来源单据类型", example = "116") @ExcelProperty(value = "来源单据类型", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_QC_SOURCE_DOC_TYPE) private Integer sourceDocType; @Schema(description = "来源单据 ID", example = "200") @@ -40,12 +45,14 @@ private Long sourceLineId; @Schema(description = "来源单据编码", example = "RT20250101001") @ExcelProperty("来源单据编码") private String sourceDocCode; // ========== 检验类型 ========== @Schema(description = "检验类型", example = "1") @ExcelProperty("检验类型") @ExcelProperty(value = "检验类型", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_RQC_TYPE) private Integer type; // ========== 物料 ========== @@ -62,9 +69,11 @@ private String itemName; @Schema(description = "规格型号", example = "100mm*50mm") @ExcelProperty("规格型号") private String itemSpecification; @Schema(description = "单位名称", example = "个") @ExcelProperty("单位") private String unitName; @Schema(description = "批次号", example = "BATCH001") @@ -108,7 +117,8 @@ // ========== 检验 ========== @Schema(description = "检测结果", example = "1") @ExcelProperty("检测结果") @ExcelProperty(value = "检测结果", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_QC_CHECK_RESULT) private Integer checkResult; @Schema(description = "检测日期") @@ -123,7 +133,8 @@ private String inspectorNickname; @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") @ExcelProperty("状态") @ExcelProperty(value = "状态", converter = DictConvert.class) @DictFormat(DictTypeConstants.MES_ORDER_STATUS) private Integer status; @Schema(description = "备注", example = "备注") yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java
@@ -76,6 +76,7 @@ String MES_DEFECT_LEVEL = "mes_defect_level"; // MES 缺陷等级 String MES_QC_TYPE = "mes_qc_type"; // MES 检测种类(IQC/IPQC/OQC/RQC) String MES_IPQC_TYPE = "mes_ipqc_type"; // MES IPQC 检验类型 String MES_RQC_TYPE = "mes_rqc_type"; // MES 退货检验类型 String MES_ORDER_STATUS = "mes_order_status"; // MES 单据状态(IQC/IPQC/OQC/RQC 通用) String MES_QC_CHECK_RESULT = "mes_qc_check_result"; // MES 检测结果 String MES_QC_SOURCE_DOC_TYPE = "mes_qc_source_doc_type"; // MES 来源单据类型 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/feedback/MesProFeedbackServiceImpl.java
@@ -296,16 +296,17 @@ throw exception(PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS, feedback.getUncheckQuantity()); } // 3. 物料消耗:倒冲工序按 BOM 自动扣料;非倒冲工序跳过(物料走手工领料/投料) // 3. 物料消耗:倒冲工序按本工序投料 BOM 自动扣料;非倒冲工序跳过(物料走手工领料/投料) boolean backflushFlag = routeProcess != null && Boolean.TRUE.equals(routeProcess.getBackflushFlag()); if (backflushFlag) { // 3.1 校验倒冲工序必须配置 BOM 消耗,避免静默不扣料 List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderId( feedback.getWorkOrderId()); // 3.1 校验倒冲工序必须配置本工序的投料 BOM,避免静默不扣料 // (只校验当前报工工序的投料,其他工序投料由各自工序报工时扣除) List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderIdAndProcessId( feedback.getWorkOrderId(), feedback.getProcessId()); if (CollUtil.isEmpty(boms)) { throw exception(PRO_FEEDBACK_BACKFLUSH_BOM_REQUIRED); } // 3.2 生成消耗记录并执行扣减(BOM × 报工数量,FIFO 扣线边库) // 3.2 生成消耗记录并执行扣减(本工序投料用量比例 × 报工数量,FIFO 扣线边库) MesWmItemConsumeDO itemConsume = itemConsumeService.generateItemConsume(feedback); if (itemConsume != null) { itemConsumeService.finishItemConsume(itemConsume.getId()); yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/route/MesProRouteProcessServiceImpl.java
@@ -81,8 +81,14 @@ public void updateRouteProcess(MesProRouteProcessSaveReqVO updateReqVO) { // 1.0 已启用的工艺路线,不允许操作 routeService.validateRouteNotEnable(updateReqVO.getRouteId()); // 1.1 校验存在 validateRouteProcessExists(updateReqVO.getId()); // 1.1 校验存在;部分更新(如仅调整产出产品)时未传的必填字段用现有值回填 MesProRouteProcessDO existing = validateRouteProcessExists(updateReqVO.getId()); if (updateReqVO.getProcessId() == null) { updateReqVO.setProcessId(existing.getProcessId()); } if (updateReqVO.getSort() == null) { updateReqVO.setSort(existing.getSort()); } // 1.2 校验工艺路线、工序存在 validateRouteAndProcessExists(updateReqVO.getRouteId(), updateReqVO.getProcessId()); // 1.3 校验唯一性 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomService.java
@@ -63,6 +63,15 @@ List<MesProWorkOrderBomDO> getWorkOrderBomListByWorkOrderId(Long workOrderId); /** * 根据工单编号与工序编号获得 BOM 列表(倒冲扣料按报工工序的投料明细过滤) * * @param workOrderId 工单编号 * @param processId 工序编号 * @return BOM 列表 */ List<MesProWorkOrderBomDO> getWorkOrderBomListByWorkOrderIdAndProcessId(Long workOrderId, Long processId); /** * 根据工单编号删除 BOM * * @param workOrderId 工单编号 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/pro/workorder/MesProWorkOrderBomServiceImpl.java
@@ -116,6 +116,11 @@ } @Override public List<MesProWorkOrderBomDO> getWorkOrderBomListByWorkOrderIdAndProcessId(Long workOrderId, Long processId) { return workOrderBomMapper.selectListByWorkOrderIdAndProcessId(workOrderId, processId); } @Override public void deleteWorkOrderBomByWorkOrderId(Long workOrderId) { workOrderBomMapper.deleteByWorkOrderId(workOrderId); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/itemconsume/MesWmItemConsumeServiceImpl.java
@@ -78,9 +78,10 @@ if (feedback.getWorkOrderId() == null) { throw exception(PRO_FEEDBACK_ROUTE_PROCESS_INVALID); } // 1.2 查询工单 BOM 物料列表(倒冲按工单投料,非工艺路线) List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderId( feedback.getWorkOrderId()); // 1.2 查询该倒冲工序的投料 BOM 列表(按报工工序过滤,只扣当前工序的投料明细, // 避免把其他工序的投料一并扣除导致多扣物料) List<MesProWorkOrderBomDO> boms = workOrderBomService.getWorkOrderBomListByWorkOrderIdAndProcessId( feedback.getWorkOrderId(), feedback.getProcessId()); if (CollUtil.isEmpty(boms)) { return null; } yudao-server/src/main/resources/application-local.yaml
@@ -74,7 +74,7 @@ redis: host: localhost # 地址 port: 6379 # 端口 database: 0 # 数据库索引 database: 5 # 数据库索引 # password: # 密码,建议生产环境开启 --- #################### 定时任务相关配置 #################### yudao-server/src/main/resources/application-yzfx.yaml
@@ -65,33 +65,10 @@ primary: master datasource: master: url: jdbc:mysql://172.17.0.1:9002/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 # url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=true&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true # MySQL Connector/J 5.X 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro # PostgreSQL 连接的示例 # url: jdbc:oracle:thin:@127.0.0.1:1521:xe # Oracle 连接的示例 # url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=ruoyi-vue-pro;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true;useUnicode=true;characterEncoding=utf-8 # SQLServer 连接的示例 # url: jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO # DM 连接的示例 # url: jdbc:kingbase8://127.0.0.1:54321/test # 人大金仓 KingbaseES 连接的示例 # url: jdbc:postgresql://127.0.0.1:5432/postgres # OpenGauss 连接的示例 # url: jdbc:postgresql://127.0.0.1:5866/ruoyi-vue-pro # 瀚高 HighGo 连接的示例 # url: jdbc:mysql://172.17.0.1:9002/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 url: jdbc:mysql://42.63.70.231:9002/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 username: root password: yzfx@123456.. # username: sa # SQL Server 连接的示例 # password: Yudao@2024 # SQL Server 连接的示例 # username: SYSDBA # DM 连接的示例 # password: SYSDBA001 # DM 连接的示例 # username: root # OpenGauss 连接的示例 # password: Yudao@2024 # OpenGauss 连接的示例 # username: root # 瀚高 HighGo 连接的示例 # password: 123456 # 瀚高 HighGo 连接的示例 # tdengine: # IoT 数据库(需要 IoT 物联网再开启噢!) # lazy: true # 开启懒加载,保证启动速度 # url: jdbc:TAOS-WS://127.0.0.1:6041/ruoyi_vue_pro?varcharAsString=true&enableAutoReconnect=true # 参见:https://t.zsxq.com/qaX9c,开启 TDengine WebSocket 自动重连 # driver-class-name: com.taosdata.jdbc.ws.WebSocketDriver # username: root # password: taosdata # druid: # validation-query: SELECT SERVER_STATUS() # TDengine 数据源的有效性检查 SQL # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 data: