2 Commits

Author SHA1 Message Date
zhouz
77db52a2b3 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	pom.xml
2026-07-17 09:30:06 +08:00
zhouz
5b643a44b4 feat:新增WMS模块。新增仓储CRUD 2026-07-17 09:26:34 +08:00
24 changed files with 2505 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-module-wms</artifactId>
<version>${revision}</version>
</parent>
<artifactId>nl-module-wms-api</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
base模块 API暴露给其它模块调用
</description>
<dependencies>
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-common</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>org.springdoc</groupId> <!-- 接口文档:使用最新版本的 Swagger 模型 -->
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<scope>provided</scope>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional>
</dependency>
<!-- RPC 远程调用相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,7 @@
package cn.code.nl.module.wms.enums;
import cn.code.nl.framework.common.exception.ErrorCode;
public interface ErrorCodeConstants {
ErrorCode BSREAL_STOR_ATTR_NOT_EXISTS = new ErrorCode(1, "实物库属性不存在");
}

View File

@@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-module-wms</artifactId>
<version>${revision}</version>
</parent>
<artifactId>nl-module-wms-server</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>
wms 模块下,我们放通用业务,支撑上层的核心业务。
功能点描述:
- xxx
- xxx
</description>
<dependencies>
<!-- Spring Cloud 基础 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-env</artifactId>
</dependency>
<!-- 依赖服务 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-module-wms-api</artifactId>
<version>${revision}</version>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-biz-data-permission</artifactId>
</dependency>
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-biz-ip</artifactId>
</dependency>
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-protection</artifactId>
</dependency>
<!-- Lock4j 分布式锁protection 中为 optional需显式引入 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>lock4j-redisson-spring-boot-starter</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-security</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-redis</artifactId>
</dependency>
<!-- RPC 远程调用相关 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-rpc</artifactId>
</dependency>
<!-- Registry 注册中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- Config 配置中心相关 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- Job 定时任务相关 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-job</artifactId>
</dependency>
<!-- 消息队列相关 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-mq</artifactId>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-excel</artifactId>
</dependency>
<!-- 监控相关 -->
<dependency>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl-spring-boot-starter-monitor</artifactId>
</dependency>
</dependencies>
<build>
<!-- 设置构建的 jar 包名 -->
<finalName>${project.artifactId}</finalName>
<plugins>
<!-- 打包 -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,16 @@
package cn.code.nl.module.wms;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
* @Author: liyongde
* @Date: 2026/7/10 9:12
*/
@SpringBootApplication
public class WmsServerApplication {
public static void main(String[] args) {
SpringApplication.run(WmsServerApplication.class, args);
}
}

View File

@@ -0,0 +1,104 @@
package cn.code.nl.module.wms.controller.admin.bsrealstorattr;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.constraints.*;
import jakarta.validation.*;
import jakarta.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.code.nl.framework.common.pojo.PageParam;
import cn.code.nl.framework.common.pojo.PageResult;
import cn.code.nl.framework.common.pojo.CommonResult;
import cn.code.nl.framework.common.util.object.BeanUtils;
import static cn.code.nl.framework.common.pojo.CommonResult.success;
import cn.code.nl.framework.excel.core.util.ExcelUtils;
import cn.code.nl.framework.apilog.core.annotation.ApiAccessLog;
import static cn.code.nl.framework.apilog.core.enums.OperateTypeEnum.*;
import cn.code.nl.module.wms.controller.admin.bsrealstorattr.vo.*;
import cn.code.nl.module.wms.dal.dataobject.bsrealstorattr.BsrealStorAttrDO;
import cn.code.nl.module.wms.service.bsrealstorattr.BsrealStorAttrService;
@Tag(name = "管理后台 - 实物库属性")
@RestController
@RequestMapping("/wms/bsreal-stor-attr")
@Validated
public class BsrealStorAttrController {
@Resource
private BsrealStorAttrService bsrealStorAttrService;
@PostMapping("/create")
@Operation(summary = "创建实物库属性")
@PreAuthorize("@ss.hasPermission('wms:bsreal-stor-attr:create')")
public CommonResult<String> createBsrealStorAttr(@Valid @RequestBody BsrealStorAttrSaveReqVO createReqVO) {
return success(bsrealStorAttrService.createBsrealStorAttr(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新实物库属性")
@PreAuthorize("@ss.hasPermission('wms:bsreal-stor-attr:update')")
public CommonResult<Boolean> updateBsrealStorAttr(@Valid @RequestBody BsrealStorAttrSaveReqVO updateReqVO) {
bsrealStorAttrService.updateBsrealStorAttr(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除实物库属性")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('wms:bsreal-stor-attr:delete')")
public CommonResult<Boolean> deleteBsrealStorAttr(@RequestParam("id") String id) {
bsrealStorAttrService.deleteBsrealStorAttr(id);
return success(true);
}
@DeleteMapping("/delete-list")
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除实物库属性")
@PreAuthorize("@ss.hasPermission('wms:bsreal-stor-attr:delete')")
public CommonResult<Boolean> deleteBsrealStorAttrList(@RequestParam("ids") List<String> ids) {
bsrealStorAttrService.deleteBsrealStorAttrListByIds(ids);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得实物库属性")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('wms:bsreal-stor-attr:query')")
public CommonResult<BsrealStorAttrRespVO> getBsrealStorAttr(@RequestParam("id") String id) {
BsrealStorAttrDO bsrealStorAttr = bsrealStorAttrService.getBsrealStorAttr(id);
return success(BeanUtils.toBean(bsrealStorAttr, BsrealStorAttrRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得实物库属性分页")
@PreAuthorize("@ss.hasPermission('wms:bsreal-stor-attr:query')")
public CommonResult<PageResult<BsrealStorAttrRespVO>> getBsrealStorAttrPage(@Valid BsrealStorAttrPageReqVO pageReqVO) {
PageResult<BsrealStorAttrDO> pageResult = bsrealStorAttrService.getBsrealStorAttrPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, BsrealStorAttrRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出实物库属性 Excel")
@PreAuthorize("@ss.hasPermission('wms:bsreal-stor-attr:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportBsrealStorAttrExcel(@Valid BsrealStorAttrPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<BsrealStorAttrDO> list = bsrealStorAttrService.getBsrealStorAttrPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "实物库属性.xls", "数据", BsrealStorAttrRespVO.class,
BeanUtils.toBean(list, BsrealStorAttrRespVO.class));
}
}

View File

@@ -0,0 +1,39 @@
package cn.code.nl.module.wms.controller.admin.bsrealstorattr.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.code.nl.framework.common.pojo.PageParam;
import java.math.BigDecimal;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.code.nl.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 实物库属性分页 Request VO")
@Data
public class BsrealStorAttrPageReqVO extends PageParam {
@Schema(description = "仓库编码")
private String storCode;
@Schema(description = "仓库名称")
private String storName;
@Schema(description = "仓库简称")
private String simpleName;
@Schema(description = "仓库性质")
private String storTypeScode;
@Schema(description = "地区")
private String area;
@Schema(description = "是否启用")
private String isUsed;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@@ -0,0 +1,148 @@
package cn.code.nl.module.wms.controller.admin.bsrealstorattr.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import cn.idev.excel.annotation.*;
@Schema(description = "管理后台 - 实物库属性 Response VO")
@Data
@ExcelIgnoreUnannotated
public class BsrealStorAttrRespVO {
@Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("仓库标识")
private String storId;
@Schema(description = "仓库编码", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("仓库编码")
private String storCode;
@Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("仓库名称")
private String storName;
@Schema(description = "仓库简称")
@ExcelProperty("仓库简称")
private String simpleName;
@Schema(description = "仓库容量")
@ExcelProperty("仓库容量")
private Integer storCapacity;
@Schema(description = "总面积")
@ExcelProperty("总面积")
private BigDecimal totalArea;
@Schema(description = "仓库性质", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("仓库性质")
private String storTypeScode;
@Schema(description = "是否虚拟库", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否虚拟库")
private String isVirtualstore;
@Schema(description = "是否半成品库", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否半成品库")
private String isSemiFinished;
@Schema(description = "是否原料库", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否原料库")
private String isMaterialstore;
@Schema(description = "是否成品库", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否成品库")
private String isProductstore;
@Schema(description = "是否备件库", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否备件库")
private String isAttachment;
@Schema(description = "是否允许红冲", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否允许红冲")
private String isReversed;
@Schema(description = "是否移出业务自动确认", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否移出业务自动确认")
private String isMvoutAutoCfm;
@Schema(description = "是否移入业务自动确认", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否移入业务自动确认")
private String isMvinAutoCfm;
@Schema(description = "地区")
@ExcelProperty("地区")
private String area;
@Schema(description = "仓库地址")
@ExcelProperty("仓库地址")
private String storeaDdress;
@Schema(description = "负责人")
@ExcelProperty("负责人")
private String principal;
@Schema(description = "办公电话")
@ExcelProperty("办公电话")
private String officePhone;
@Schema(description = "负责人手机")
@ExcelProperty("负责人手机")
private String mobileNo;
@Schema(description = "备注", example = "你猜")
@ExcelProperty("备注")
private String remark;
@Schema(description = "显示顺序")
@ExcelProperty("显示顺序")
private Integer orderIndex;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("状态")
private String whstateScode;
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否启用")
private String isUsed;
@Schema(description = "物料基本分类", example = "6627")
@ExcelProperty("物料基本分类")
private String baseClassId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "拥有者ID", example = "20565")
@ExcelProperty("拥有者ID")
private String sysownerid;
@Schema(description = "部门ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "26732")
@ExcelProperty("部门ID")
private String sysdeptid;
@Schema(description = "公司ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "21831")
@ExcelProperty("公司ID")
private String syscompanyid;
@Schema(description = "是否删除", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("是否删除")
private String isDelete;
@Schema(description = "外部标识", example = "18176")
@ExcelProperty("外部标识")
private String extId;
@Schema(description = "部门名称", example = "李四")
@ExcelProperty("部门名称")
private String departName;
@Schema(description = "公司名称", example = "芋艿")
@ExcelProperty("公司名称")
private String companyName;
}

View File

@@ -0,0 +1,111 @@
package cn.code.nl.module.wms.controller.admin.bsrealstorattr.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
@Schema(description = "管理后台 - 实物库属性新增/修改 Request VO")
@Data
public class BsrealStorAttrSaveReqVO {
@Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED)
private String storId;
@Schema(description = "仓库编码", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "仓库编码不能为空")
private String storCode;
@Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "仓库名称不能为空")
private String storName;
@Schema(description = "仓库简称")
private String simpleName;
@Schema(description = "仓库容量")
private Integer storCapacity;
@Schema(description = "总面积")
private BigDecimal totalArea;
@Schema(description = "仓库性质", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "仓库性质不能为空")
private String storTypeScode;
@Schema(description = "是否虚拟库")
private String isVirtualstore;
@Schema(description = "是否半成品库")
private String isSemiFinished;
@Schema(description = "是否原料库")
private String isMaterialstore;
@Schema(description = "是否成品库")
private String isProductstore;
@Schema(description = "是否备件库")
private String isAttachment;
@Schema(description = "是否允许红冲")
private String isReversed;
@Schema(description = "是否移出业务自动确认")
private String isMvoutAutoCfm;
@Schema(description = "是否移入业务自动确认")
private String isMvinAutoCfm;
@Schema(description = "地区")
private String area;
@Schema(description = "仓库地址")
private String storeaDdress;
@Schema(description = "负责人")
private String principal;
@Schema(description = "办公电话")
private String officePhone;
@Schema(description = "负责人手机")
private String mobileNo;
@Schema(description = "备注", example = "你猜")
private String remark;
@Schema(description = "显示顺序")
private Integer orderIndex;
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "状态不能为空")
private String whstateScode;
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "是否启用不能为空")
private String isUsed;
@Schema(description = "物料基本分类", example = "6627")
private String baseClassId;
@Schema(description = "拥有者ID", example = "20565")
private String sysownerid;
@Schema(description = "部门ID", example = "26732")
private String sysdeptid;
@Schema(description = "公司ID", example = "21831")
private String syscompanyid;
@Schema(description = "外部标识", example = "18176")
private String extId;
@Schema(description = "部门名称", example = "李四")
private String departName;
@Schema(description = "公司名称", example = "芋艿")
private String companyName;
}

View File

@@ -0,0 +1,153 @@
package cn.code.nl.module.wms.dal.dataobject.bsrealstorattr;
import lombok.*;
import java.util.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.code.nl.framework.mybatis.core.dataobject.BaseDO;
/**
* 实物库属性 DO
*
* @author 诺力管理员
*/
@TableName("wms_bsrealstorattr")
@KeySequence("wms_bsrealstorattr_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BsrealStorAttrDO extends BaseDO {
/**
* 仓库标识
*/
@TableId
private String storId;
/**
* 仓库编码
*/
private String storCode;
/**
* 仓库名称
*/
private String storName;
/**
* 仓库简称
*/
private String simpleName;
/**
* 仓库容量
*/
private Integer storCapacity;
/**
* 总面积
*/
private BigDecimal totalArea;
/**
* 仓库性质
*/
private String storTypeScode;
/**
* 是否虚拟库
*/
private String isVirtualstore;
/**
* 是否半成品库
*/
private String isSemiFinished;
/**
* 是否原料库
*/
private String isMaterialstore;
/**
* 是否成品库
*/
private String isProductstore;
/**
* 是否备件库
*/
private String isAttachment;
/**
* 是否允许红冲
*/
private String isReversed;
/**
* 是否移出业务自动确认
*/
private String isMvoutAutoCfm;
/**
* 是否移入业务自动确认
*/
private String isMvinAutoCfm;
/**
* 地区
*/
private String area;
/**
* 仓库地址
*/
private String storeaDdress;
/**
* 负责人
*/
private String principal;
/**
* 办公电话
*/
private String officePhone;
/**
* 负责人手机
*/
private String mobileNo;
/**
* 备注
*/
private String remark;
/**
* 显示顺序
*/
private Integer orderIndex;
/**
* 状态
*/
private String whstateScode;
/**
* 是否启用
*/
private String isUsed;
/**
* 物料基本分类
*/
private String baseClassId;
/**
* 拥有者ID
*/
private String sysownerid;
/**
* 部门ID
*/
private String sysdeptid;
/**
* 公司ID
*/
private String syscompanyid;
/**
* 外部标识
*/
private String extId;
/**
* 部门名称
*/
private String departName;
/**
* 公司名称
*/
private String companyName;
}

View File

@@ -0,0 +1,32 @@
package cn.code.nl.module.wms.dal.mysql.bsrealstorattr;
import java.util.*;
import cn.code.nl.framework.common.pojo.PageResult;
import cn.code.nl.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.code.nl.framework.mybatis.core.mapper.BaseMapperX;
import cn.code.nl.module.wms.dal.dataobject.bsrealstorattr.BsrealStorAttrDO;
import org.apache.ibatis.annotations.Mapper;
import cn.code.nl.module.wms.controller.admin.bsrealstorattr.vo.*;
/**
* 实物库属性 Mapper
*
* @author 诺力管理员
*/
@Mapper
public interface BsrealStorAttrMapper extends BaseMapperX<BsrealStorAttrDO> {
default PageResult<BsrealStorAttrDO> selectPage(BsrealStorAttrPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<BsrealStorAttrDO>()
.eqIfPresent(BsrealStorAttrDO::getStorCode, reqVO.getStorCode())
.likeIfPresent(BsrealStorAttrDO::getStorName, reqVO.getStorName())
.likeIfPresent(BsrealStorAttrDO::getSimpleName, reqVO.getSimpleName())
.eqIfPresent(BsrealStorAttrDO::getStorTypeScode, reqVO.getStorTypeScode())
.eqIfPresent(BsrealStorAttrDO::getArea, reqVO.getArea())
.eqIfPresent(BsrealStorAttrDO::getIsUsed, reqVO.getIsUsed())
.betweenIfPresent(BsrealStorAttrDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(BsrealStorAttrDO::getStorId));
}
}

View File

@@ -0,0 +1,117 @@
package cn.code.nl.module.wms.framework.security.config;
import cn.code.nl.framework.security.config.AuthorizeRequestsCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
/**
* Base 模块的 Security 配置
*
* @author zhouz
*/
@Configuration(proxyBeanMethods = false, value = "baseSecurityConfiguration")
public class SecurityConfiguration {
/*
*
* 根因确认
问题出在 NlWebSecurityConfigurerAdapter.java:77-78
@Resource // 第77行
private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers;
@Resource 在处理 List<T> 泛型注入时的行为与 @Autowired 不同:
- @Autowired 能正确按元素类型 T 解析,即使 0 个 Bean 也能注入空集合
- @Resource 先按字段名查找,失败后按原始类型回退匹配。由于泛型擦除,类型变成了原始 java.util.ListSpring 找不到类型为 java.util.List 的 Bean直接报错
为什么 infra 模块正常? infra 模块的 SecurityConfiguration 定义了 1 个 AuthorizeRequestsCustomizer Bean@Resource 的非空集合路径能正确处理。而 base 模块有
0 个这样的 Bean触发了空集合路径的 bug。
修复方式: 为 base 模块创建 SecurityConfiguration已创建这是该项目的标准模式每个模块定义自己的安全配置
现在验证修改:
Thought for 6s, read 1 file (ctrl+o to expand)
⏺ 配置已创建。让我验证一下文件结构是否完整:
Thought for 5s, searched for 1 pattern (ctrl+o to expand)
⏺ 总结
问题根因
NlWebSecurityConfigurerAdapter.java:77-78 中使用了 @Resource 注入 List<AuthorizeRequestsCustomizer>
@Resource
private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers;
@Resource 在处理泛型集合时存在局限性,按字段名查找失败后会按原始类型 java.util.List 回退匹配,导致 Spring 找不到对应 Bean 而报错。@Autowired
能正确处理这种情况(包括空集合),但 @Resource 不行。
修复内容
创建了 base 模块的 SecurityConfiguration参考 infra 模块的同等配置):
nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/framework/security/config/SecurityConfiguration.java
这个配置类:
1. 定义了一个 AuthorizeRequestsCustomizer Bean使 NlWebSecurityConfigurerAdapter 中的 List<AuthorizeRequestsCustomizer> 能正确解析
1. 定义了一个 AuthorizeRequestsCustomizer Bean使 NlWebSecurityConfigurerAdapter 中的 List<AuthorizeRequestsCustomizer> 能正确解析
Thought for 5s, searched for 1 pattern (ctrl+o to expand)
⏺ 总结
问题根因
NlWebSecurityConfigurerAdapter.java:77-78 中使用了 @Resource 注入
List<AuthorizeRequestsCustomizer>
@Resource
private List<AuthorizeRequestsCustomizer> authorizeRequestsCustomizers;
@Resource 在处理泛型集合时存在局限性,按字段名查找失败后会按原始类型
java.util.List 回退匹配,导致 Spring 找不到对应 Bean 而报错。@Autowired
能正确处理这种情况(包括空集合),但 @Resource 不行。
修复内容
创建了 base 模块的 SecurityConfiguration参考 infra 模块的同等配置):
nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/fr
amework/security/config/SecurityConfiguration.java
nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/framework/security/config/SecurityConfiguration.java
这个配置类:
1. 定义了一个 AuthorizeRequestsCustomizer Bean使 NlWebSecurityConfigurerAdapter 中的 List<AuthorizeRequestsCustomizer> 能正确解析
2. 配置了 Swagger、Actuator、Druid 等公共路径的免登录访问
3. 遵循了项目中每个模块定义各自安全配置的标准模式
3. 遵循了项目中每个模块定义各自安全配置的标准模式
* */
@Bean("baseAuthorizeRequestsCustomizer")
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
return new AuthorizeRequestsCustomizer() {
@Override
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
// Swagger 接口文档
registry.requestMatchers("/v3/api-docs/**").permitAll()
.requestMatchers("/webjars/**").permitAll()
.requestMatchers("/swagger-ui").permitAll()
.requestMatchers("/swagger-ui/**").permitAll();
// Spring Boot Actuator 的安全配置
registry.requestMatchers("/actuator").permitAll()
.requestMatchers("/actuator/**").permitAll();
// Druid 监控
registry.requestMatchers("/druid/**").permitAll();
}
};
}
}

View File

@@ -0,0 +1,62 @@
package cn.code.nl.module.wms.service.bsrealstorattr;
import java.util.*;
import jakarta.validation.*;
import cn.code.nl.module.wms.controller.admin.bsrealstorattr.vo.*;
import cn.code.nl.module.wms.dal.dataobject.bsrealstorattr.BsrealStorAttrDO;
import cn.code.nl.framework.common.pojo.PageResult;
import cn.code.nl.framework.common.pojo.PageParam;
/**
* 实物库属性 Service 接口
*
* @author 诺力管理员
*/
public interface BsrealStorAttrService {
/**
* 创建实物库属性
*
* @param createReqVO 创建信息
* @return 编号
*/
String createBsrealStorAttr(@Valid BsrealStorAttrSaveReqVO createReqVO);
/**
* 更新实物库属性
*
* @param updateReqVO 更新信息
*/
void updateBsrealStorAttr(@Valid BsrealStorAttrSaveReqVO updateReqVO);
/**
* 删除实物库属性
*
* @param id 编号
*/
void deleteBsrealStorAttr(String id);
/**
* 批量删除实物库属性
*
* @param ids 编号
*/
void deleteBsrealStorAttrListByIds(List<String> ids);
/**
* 获得实物库属性
*
* @param id 编号
* @return 实物库属性
*/
BsrealStorAttrDO getBsrealStorAttr(String id);
/**
* 获得实物库属性分页
*
* @param pageReqVO 分页查询
* @return 实物库属性分页
*/
PageResult<BsrealStorAttrDO> getBsrealStorAttrPage(BsrealStorAttrPageReqVO pageReqVO);
}

View File

@@ -0,0 +1,85 @@
package cn.code.nl.module.wms.service.bsrealstorattr;
import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.code.nl.module.wms.controller.admin.bsrealstorattr.vo.*;
import cn.code.nl.module.wms.dal.dataobject.bsrealstorattr.BsrealStorAttrDO;
import cn.code.nl.framework.common.pojo.PageResult;
import cn.code.nl.framework.common.pojo.PageParam;
import cn.code.nl.framework.common.util.object.BeanUtils;
import cn.code.nl.module.wms.dal.mysql.bsrealstorattr.BsrealStorAttrMapper;
import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.code.nl.framework.common.util.collection.CollectionUtils.convertList;
import static cn.code.nl.framework.common.util.collection.CollectionUtils.diffList;
import static cn.code.nl.module.wms.enums.ErrorCodeConstants.*;
/**
* 实物库属性 Service 实现类
*
* @author 诺力管理员
*/
@Service
@Validated
public class BsrealStorAttrServiceImpl implements BsrealStorAttrService {
@Resource
private BsrealStorAttrMapper bsrealStorAttrMapper;
@Override
public String createBsrealStorAttr(BsrealStorAttrSaveReqVO createReqVO) {
// 插入
BsrealStorAttrDO bsrealStorAttr = BeanUtils.toBean(createReqVO, BsrealStorAttrDO.class);
bsrealStorAttrMapper.insert(bsrealStorAttr);
// 返回
return bsrealStorAttr.getStorId();
}
@Override
public void updateBsrealStorAttr(BsrealStorAttrSaveReqVO updateReqVO) {
// 校验存在
validateBsrealStorAttrExists(updateReqVO.getStorId());
// 更新
BsrealStorAttrDO updateObj = BeanUtils.toBean(updateReqVO, BsrealStorAttrDO.class);
bsrealStorAttrMapper.updateById(updateObj);
}
@Override
public void deleteBsrealStorAttr(String id) {
// 校验存在
validateBsrealStorAttrExists(id);
// 删除
bsrealStorAttrMapper.deleteById(id);
}
@Override
public void deleteBsrealStorAttrListByIds(List<String> ids) {
// 删除
bsrealStorAttrMapper.deleteByIds(ids);
}
private void validateBsrealStorAttrExists(String id) {
if (bsrealStorAttrMapper.selectById(id) == null) {
throw exception(BSREAL_STOR_ATTR_NOT_EXISTS);
}
}
@Override
public BsrealStorAttrDO getBsrealStorAttr(String id) {
return bsrealStorAttrMapper.selectById(id);
}
@Override
public PageResult<BsrealStorAttrDO> getBsrealStorAttrPage(BsrealStorAttrPageReqVO pageReqVO) {
return bsrealStorAttrMapper.selectPage(pageReqVO);
}
}

View File

@@ -0,0 +1,142 @@
--- #################### 注册中心 + 配置中心相关配置 ####################
spring:
cloud:
nacos:
server-addr: http://192.168.81.193:8848 # Nacos 服务器地址
username: nacos
password: nacos
discovery: # 【配置中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
metadata:
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
--- #################### 数据库相关配置 ####################
spring:
# 数据源配置项
autoconfigure:
exclude:
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
enabled: true
stat-view-servlet:
enabled: true
allow: # 设置白名单,不填则允许所有访问
url-pattern: /druid/*
login-username: # 控制台管理用户名和密码
login-password:
filter:
stat:
enabled: true
log-slow-sql: true # 慢 SQL 记录
slow-sql-millis: 100
merge-sql: true
wall:
config:
multi-statement-allow: true
dynamic: # 多数据源配置
druid: # Druid 【连接池】相关的全局配置
initial-size: 5 # 初始连接数
min-idle: 10 # 最小连接池数量
max-active: 20 # 最大连接池数量
max-wait: 60000 # 配置获取连接等待超时的时间单位毫秒1 分钟)
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测检测需要关闭的空闲连接单位毫秒1 分钟)
min-evictable-idle-time-millis: 600000 # 配置一个连接在池中最小生存的时间单位毫秒10 分钟)
max-evictable-idle-time-millis: 1800000 # 配置一个连接在池中最大生存的时间单位毫秒30 分钟)
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true # 是否开启 PreparedStatement 缓存
max-pool-prepared-statement-per-connection-size: 20 # 每个连接缓存的 PreparedStatement 数量
primary: master
datasource:
master:
url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
password: root123
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://192.168.81.193:3306/huachuang_lms_dev?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
password: root123
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis:
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################
# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
name-server: 127.0.0.1:9876 # RocketMQ Namesrv
spring:
# RabbitMQ 配置项,对应 RabbitProperties 配置类
rabbitmq:
host: 127.0.0.1 # RabbitMQ 服务的地址
port: 5672 # RabbitMQ 服务的端口
username: guest # RabbitMQ 服务的账号
password: guest # RabbitMQ 服务的密码
# Kafka 配置项,对应 KafkaProperties 配置类
kafka:
bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔
--- #################### 定时任务相关配置 ####################
xxl:
job:
admin:
addresses: http://localhost:8080/xxl-job-admin # 调度中心部署跟地址
executor:
ip: localhost
port: 9992
--- #################### 服务保障相关配置 ####################
# Lock4j 配置项
lock4j:
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
expire: 30000 # 分布式锁的超时时间,默认为 30000 毫秒
--- #################### 监控相关配置 ####################
# Actuator 监控端点的配置项
management:
endpoints:
web:
base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
exposure:
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# Spring Boot Admin 配置项
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
instance:
service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
username: admin
password: admin
# Spring Boot Admin Server 服务端的相关配置
context-path: /admin # 配置 Spring
# 日志文件配置
logging:
file:
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
--- #################### 芋道相关配置 ####################
# 芋道配置项,设置当前项目所有自定义的配置
nl:
demo: false # 开启演示模式

View File

@@ -0,0 +1,142 @@
--- #################### 注册中心 + 配置中心相关配置 ####################
spring:
cloud:
nacos:
server-addr: http://localhost:8848 # Nacos 服务器地址
username: # Nacos 账号
password: # Nacos 密码
discovery: # 【配置中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
metadata:
version: 1.0.0 # 服务实例的版本号,可用于灰度发布
config: # 【注册中心】配置项
namespace: dev # 命名空间。这里使用 dev 开发环境
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
--- #################### 数据库相关配置 ####################
spring:
# 数据源配置项
autoconfigure:
exclude:
datasource:
druid: # Druid 【监控】相关的全局配置
web-stat-filter:
enabled: true
stat-view-servlet:
enabled: true
allow: # 设置白名单,不填则允许所有访问
url-pattern: /druid/*
login-username: # 控制台管理用户名和密码
login-password:
filter:
stat:
enabled: true
log-slow-sql: true # 慢 SQL 记录
slow-sql-millis: 100
merge-sql: true
wall:
config:
multi-statement-allow: true
dynamic: # 多数据源配置
druid: # Druid 【连接池】相关的全局配置
initial-size: 5 # 初始连接数
min-idle: 10 # 最小连接池数量
max-active: 20 # 最大连接池数量
max-wait: 60000 # 配置获取连接等待超时的时间单位毫秒1 分钟)
time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测检测需要关闭的空闲连接单位毫秒1 分钟)
min-evictable-idle-time-millis: 600000 # 配置一个连接在池中最小生存的时间单位毫秒10 分钟)
max-evictable-idle-time-millis: 1800000 # 配置一个连接在池中最大生存的时间单位毫秒30 分钟)
validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true # 是否开启 PreparedStatement 缓存
max-pool-prepared-statement-per-connection-size: 20 # 每个连接缓存的 PreparedStatement 数量
primary: master
datasource:
master:
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
password: 12356
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
username: root
password: root
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data:
redis:
host: 127.0.0.1 # 地址
port: 6379 # 端口
database: 1 # 数据库索引
# password: 123456 # 密码,建议生产环境开启
--- #################### MQ 消息队列相关配置 ####################
# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
name-server: 127.0.0.1:9876 # RocketMQ Namesrv
spring:
# RabbitMQ 配置项,对应 RabbitProperties 配置类
rabbitmq:
host: 127.0.0.1 # RabbitMQ 服务的地址
port: 5672 # RabbitMQ 服务的端口
username: guest # RabbitMQ 服务的账号
password: guest # RabbitMQ 服务的密码
# Kafka 配置项,对应 KafkaProperties 配置类
kafka:
bootstrap-servers: 127.0.0.1:9092 # 指定 Kafka Broker 地址,可以设置多个,以逗号分隔
--- #################### 定时任务相关配置 ####################
xxl:
job:
admin:
addresses: http://localhost:8080/xxl-job-admin # 调度中心部署跟地址
executor:
ip: localhost
port: 9992
--- #################### 服务保障相关配置 ####################
# Lock4j 配置项
lock4j:
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
expire: 30000 # 分布式锁的超时时间,默认为 30000 毫秒
--- #################### 监控相关配置 ####################
# Actuator 监控端点的配置项
management:
endpoints:
web:
base-path: /actuator # Actuator 提供的 API 接口的根目录。默认为 /actuator
exposure:
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
# Spring Boot Admin 配置项
spring:
boot:
admin:
# Spring Boot Admin Client 客户端的相关配置
client:
instance:
service-host-type: IP # 注册实例时,优先使用 IP [IP, HOST_NAME, CANONICAL_HOST_NAME]
username: admin
password: admin
# Spring Boot Admin Server 服务端的相关配置
context-path: /admin # 配置 Spring
# 日志文件配置
logging:
file:
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
--- #################### 芋道相关配置 ####################
# 芋道配置项,设置当前项目所有自定义的配置
nl:
demo: false # 开启演示模式

View File

@@ -0,0 +1,149 @@
spring:
application:
name: wms-server
profiles:
active: dev
main:
allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
allow-bean-definition-overriding: true # 允许 Bean 覆盖,例如说 Feign 等会存在重复定义的服务
config:
import:
- optional:classpath:application-${spring.profiles.active}.yaml # 加载【本地】配置
- optional:nacos:${spring.application.name}-${spring.profiles.active}.yaml # 加载【Nacos】的配置
# Servlet 配置
servlet:
# 文件上传相关配置项
multipart:
max-file-size: 16MB # 单个文件大小
max-request-size: 32MB # 设置总上传的文件大小
# Jackson 配置项
jackson:
serialization:
write-dates-as-timestamps: true # 设置 LocalDateTime 的格式,使用时间戳
write-date-timestamps-as-nanoseconds: false # 设置不使用 nanoseconds 的格式。例如说 1611460870.401,而是直接 1611460870401
write-durations-as-timestamps: true # 设置 Duration 的格式,使用时间戳
fail-on-empty-beans: false # 允许序列化无属性的 Bean
# Cache 配置项
cache:
type: REDIS
redis:
time-to-live: 1h # 设置过期时间为 1 小时
server:
port: 48085
logging:
file:
name: ${user.home}/logs/${spring.application.name}.log # 日志文件名,全路径
--- #################### 接口文档配置 ####################
springdoc:
api-docs:
enabled: true # 1. 是否开启 Swagger 接文档的元数据
path: /v3/api-docs
swagger-ui:
enabled: true # 2.1 是否开启 Swagger 文档的官方 UI 界面
path: /swagger-ui
default-flat-param-object: true # 参见 https://doc.xiaominfo.com/docs/faq/v4/knife4j-parameterobject-flat-param 文档
knife4j:
enable: true
setting:
language: zh_cn
# MyBatis Plus 的配置项
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
global-config:
db-config:
#id-type: NONE # “智能”模式,基于 IdTypeEnvironmentPostProcessor + 数据源的类型,自动适配成 AUTO、INPUT 模式。
# id-type: AUTO # 自增 ID适合 MySQL 等直接自增的数据库
# id-type: INPUT # 用户输入 ID适合 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库
id-type: ASSIGN_ID # 分配 ID默认使用雪花算法。注意Oracle、PostgreSQL、Kingbase、DB2、H2 数据库时,需要去除实体类上的 @KeySequence 注解
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
banner: false # 关闭控制台的 Banner 打印
type-aliases-package: ${nl.info.base-package}.dal.dataobject
encryptor:
password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成
mybatis-plus-join:
banner: false # 关闭控制台的 Banner 打印
# Spring Data Redis 配置
spring:
data:
redis:
repositories:
enabled: false # 项目未使用到 Spring Data Redis 的 Repository所以直接禁用保证启动速度
# VO 转换(数据翻译)相关
easy-trans:
is-enable-global: false # 【默认禁用,对性能确认压力大】启用全局翻译(拦截所有 SpringMVC ResponseBody 进行自动翻译 )。如果对于性能要求很高可关闭此配置,或通过 @IgnoreTrans 忽略某个接口
--- #################### RPC 远程调用相关配置 ####################
--- #################### 消息队列相关 ####################
# rocketmq 配置项,对应 RocketMQProperties 配置类
rocketmq:
# Producer 配置项
producer:
group: ${spring.application.name}_PRODUCER # 生产者分组
--- #################### 定时任务相关配置 ####################
xxl:
job:
executor:
appname: ${spring.application.name} # 执行器 AppName
logpath: ${user.home}/logs/xxl-job/${spring.application.name} # 执行器运行日志文件存储磁盘路径
accessToken: 123456 # 执行器通讯TOKEN
--- #################### 芋道相关配置 ####################
nl:
info:
version: 1.0.0
base-package: cn.code.nl.module.wms
web:
admin-ui:
url: http://dashboard.nl.iocoder.cn # Admin 管理后台 UI 的地址
xss:
enable: false
exclude-urls: # 如下 url仅仅是为了演示去掉配置也没关系
- ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
api-encrypt:
enable: true # 是否开启 API 加密
algorithm: AES # 加密算法,支持 AES、RSA 等
request-key: 52549111389893486934626385991395 # 【AES 案例】请求加密的秘钥,,必须 16、24、32 位
response-key: 96103715984234343991809655248883 # 【AES 案例】响应加密的秘钥AES 案例,必须 16、24、32 位
# request-key: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKWzasimcZ1icsWDPVdTXcZs1DkOWjI+m9bTQU8aOqflnomkr6QO1WWeSHBHzuJGsTlV/ZY2pFfq/NstKC94hBjx7yioYJvzb2bKN/Uy4j5nM3iCF//u0RiFkkY8j0Bt/EWoFTOb6RHf8cHIAjbYYtP3pYzbpCIwryfe0g//KIuzAgMBAAECgYADDjZrYcpZjR2xr7RbXmGtzYbyUGXwZEAqa3XaWBD51J2iSyOkAlQEDjGmxGQ3vvb4qDHHadWI+3/TKNeDXJUO+xTVJrnismK5BsHyC6dfxlIK/5BAuknryTca/3UoA1yomS9ZlF3Q0wcecaDoEnSmZEaTrp9T3itPAz4KnGjv5QJBAN5mNcfu6iJ5ktNvEdzqcxkKwbXb9Nq1SLnmTvt+d5TPX7eQ9fCwtOfVu5iBLhhZzb5PJ7pSN3Zt6rl5/jPOGv0CQQC+vETX9oe1wbxZSv6/RBGy0Xow6GndbJwvd89PcAJ2h+OJXWtg/rRHB3t9EQm7iis0XbZTapj19E4U6l8EibhvAkEA1CvYpRwmHKu1SqdM+GBnW/2qHlBwwXJvpoK02TOm674HR/4w0+YRQJfkd7LOAgcyxJuJgDTNmtt0MmzS+iNoFQJAMVSUIZ77XoDq69U/qcw7H5qaFcgmiUQr6QL9tTftCyb+LGri+MUnby96OtCLSdvkbLjIDS8GvKYhA7vSM2RDNQJBAKGyVVnFFIrbK3yuwW71yvxQEGoGxlgvZSezZ4vGgqTxrr9HvAtvWLwR6rpe6ybR/x8uUtoW7NRBWgpiIFwjvY4= # 【RSA 案例】请求解密的私钥
# response-key: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDh/CHyBcS/zEfVyINVA7+c9Xxl0CPdxPMK1OIjxaLy/7BLfbkoEpI8onQtjuzfpuxCraDem9bu3BMF0pMH95HytI3Vi0kGjaV+WLIalwgc2w37oA2sbsmKzQOP7SDLO5s2QJNAD7kVwd+Q5rqaLu2MO0xVv+0IUJhn83hClC0L5wIDAQAB # 【RSA 案例】响应加密的公钥
swagger:
title: 管理后台
description: 提供管理员管理的所有功能
version: ${nl.info.version}
tenant: # 多租户相关配置项
enable: false
ignore-urls:
ignore-visit-urls:
- /admin-api/wms/**
ignore-tables:
ignore-caches:
sms-code: # 短信验证码相关的配置项
expire-times: 10m
send-frequency: 1m
send-maximum-quantity-per-day: 10
begin-code: 9999 # 这里配置 9999 的原因是,测试方便。
end-code: 9999 # 这里配置 9999 的原因是,测试方便。
debug: false

View File

@@ -0,0 +1,56 @@
<configuration>
<!-- 参考 org/springframework/boot/logging/logback/defaults.xml 配置,优化 CONSOLE_LOG_PATTERN、FILE_LOG_PATTERN -->
<!-- 格式化输出:%d 表示日期,%thread 表示线程名,%-5level级别从左显示 5 个字符宽度,%msg日志消息%n是换行符 -->
<!-- CONSOLE_LOG_PATTERN 相比 FILE_LOG_PATTERN 多了 highlight、cyan 等高亮 -->
<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{50}:%L) - %msg%n"/>
<property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n"/>
<!-- 控制台 Appender -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">     
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 文件 Appender -->
<!-- 参考 Spring Boot 的 file-appender.xml 编写 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
<!-- 日志文件名 -->
<file>${LOG_FILE}</file>
<!-- 滚动策略:基于【每天 + 大小】创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern> <!-- 日志文件输出的文件名 -->
<maxHistory>30</maxHistory> <!-- 日志文件的保留天数 -->
<maxFileSize>10MB</maxFileSize> <!-- 日志文件,到达多少容量,进行滚动 -->
</rollingPolicy>
</appender>
<!-- 异步写入日志,提升性能 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<discardingThreshold>0</discardingThreshold> <!-- 不丢失日志。默认的,如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
<queueSize>512</queueSize> <!-- 更改默认的队列的深度,该值会影响性能。默认值为 256 -->
<appender-ref ref="FILE"/>
</appender>
<!-- SkyWalking AppenderGRPC 日志收集,实现日志中心 -->
<!--
<appender name="SKYWALKING" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout">
<pattern>[%tid] ${FILE_LOG_PATTERN}</pattern>
</layout>
</encoder>
</appender>
-->
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<!-- 本地环境下如果不想【FILE】打印日志可以注释掉本行 -->
<appender-ref ref="ASYNC"/>
<!-- 如果想接入【SkyWalking 日志服务】,可以取消注释掉本行 -->
<!-- <appender-ref ref="SKYWALKING"/> -->
</root>
</configuration>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.code.nl.module.wms.dal.mysql.bsrealstorattr.BsrealStorAttrMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

25
nl-module-wms/pom.xml Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.nl.cloud</groupId>
<artifactId>nl</artifactId>
<version>${revision}</version>
</parent>
<artifactId>nl-module-wms</artifactId>
<packaging>pom</packaging>
<name>${project.artifactId}</name>
<description>
wms 模块下我们放仓储的核心业务提供API。
</description>
<modules>
<module>nl-module-wms-api</module>
<module>nl-module-wms-server</module>
</modules>
</project>

View File

@@ -0,0 +1,82 @@
import type { PageParam, PageResult } from '@vben/request';
import { requestClient } from '#/api/request';
export namespace WmsBsrealStorAttrApi {
/** 实物库属性信息 */
export interface BsrealStorAttr {
storId: string; // 仓库标识
storCode?: string; // 仓库编码
storName?: string; // 仓库名称
simpleName: string; // 仓库简称
storCapacity: number; // 仓库容量
totalArea: number; // 总面积
storTypeScode?: string; // 仓库性质
isVirtualstore?: string; // 是否虚拟库
isSemiFinished?: string; // 是否半成品库
isMaterialstore?: string; // 是否原料库
isProductstore?: string; // 是否成品库
isAttachment?: string; // 是否备件库
isReversed?: string; // 是否允许红冲
isMvoutAutoCfm?: string; // 是否移出业务自动确认
isMvinAutoCfm?: string; // 是否移入业务自动确认
area: string; // 地区
storeaDdress: string; // 仓库地址
principal: string; // 负责人
officePhone: string; // 办公电话
mobileNo: string; // 负责人手机
remark: string; // 备注
orderIndex: number; // 显示顺序
whstateScode?: string; // 状态
isUsed?: string; // 是否启用
baseClassId: string; // 物料基本分类
sysownerid: string; // 拥有者ID
sysdeptid?: string; // 部门ID
syscompanyid?: string; // 公司ID
extId: string; // 外部标识
departName: string; // 部门名称
companyName: string; // 公司名称
}
}
/** 查询实物库属性分页 */
export function getBsrealStorAttrPage(params: PageParam) {
return requestClient.get<PageResult<WmsBsrealStorAttrApi.BsrealStorAttr>>(
'/wms/bsreal-stor-attr/page',
{ params },
);
}
/** 查询实物库属性详情 */
export function getBsrealStorAttr(id: number) {
return requestClient.get<WmsBsrealStorAttrApi.BsrealStorAttr>(
`/wms/bsreal-stor-attr/get?id=${id}`,
);
}
/** 新增实物库属性 */
export function createBsrealStorAttr(data: WmsBsrealStorAttrApi.BsrealStorAttr) {
return requestClient.post('/wms/bsreal-stor-attr/create', data);
}
/** 修改实物库属性 */
export function updateBsrealStorAttr(data: WmsBsrealStorAttrApi.BsrealStorAttr) {
return requestClient.put('/wms/bsreal-stor-attr/update', data);
}
/** 删除实物库属性 */
export function deleteBsrealStorAttr(id: number) {
return requestClient.delete(`/wms/bsreal-stor-attr/delete?id=${id}`);
}
/** 批量删除实物库属性 */
export function deleteBsrealStorAttrList(ids: number[]) {
return requestClient.delete(
`/wms/bsreal-stor-attr/delete-list?ids=${ids.join(',')}`,
);
}
/** 导出实物库属性 */
export function exportBsrealStorAttr(params: any) {
return requestClient.download('/wms/bsreal-stor-attr/export-excel', { params });
}

View File

@@ -0,0 +1,566 @@
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { WmsBsrealStorAttrApi } from '#/api/wms/bsrealstorattr';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
import { getRangePickerDefaultProps } from '#/utils';
/** 新增/修改的表单 */
export function useFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'id',
component: 'Input',
dependencies: {
triggerFields: [''],
show: () => false,
},
},
{
fieldName: 'storCode',
label: '仓库编码',
rules: 'required',
component: 'Input',
componentProps: {
placeholder: '请输入仓库编码',
},
},
{
fieldName: 'storName',
label: '仓库名称',
rules: 'required',
component: 'Input',
componentProps: {
placeholder: '请输入仓库名称',
},
},
{
fieldName: 'simpleName',
label: '仓库简称',
component: 'Input',
componentProps: {
placeholder: '请输入仓库简称',
},
},
{
fieldName: 'storCapacity',
label: '仓库容量',
component: 'Input',
componentProps: {
placeholder: '请输入仓库容量',
},
},
{
fieldName: 'totalArea',
label: '总面积',
component: 'Input',
componentProps: {
placeholder: '请输入总面积',
},
},
{
fieldName: 'storTypeScode',
label: '仓库性质',
rules: 'required',
component: 'Input',
componentProps: {
placeholder: '请输入仓库性质',
},
},
{
fieldName: 'isVirtualstore',
label: '是否虚拟库',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'isSemiFinished',
label: '是否半成品库',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'isMaterialstore',
label: '是否原料库',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'isProductstore',
label: '是否成品库',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'isAttachment',
label: '是否备件库',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'isReversed',
label: '是否允许红冲',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'isMvoutAutoCfm',
label: '是否移出业务自动确认',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'isMvinAutoCfm',
label: '是否移入业务自动确认',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'area',
label: '地区',
component: 'Input',
componentProps: {
placeholder: '请输入地区',
},
},
{
fieldName: 'storeaDdress',
label: '仓库地址',
component: 'Input',
componentProps: {
placeholder: '请输入仓库地址',
},
},
{
fieldName: 'principal',
label: '负责人',
component: 'Input',
componentProps: {
placeholder: '请输入负责人',
},
},
{
fieldName: 'officePhone',
label: '办公电话',
component: 'Input',
componentProps: {
placeholder: '请输入办公电话',
},
},
{
fieldName: 'mobileNo',
label: '负责人手机',
component: 'Input',
componentProps: {
placeholder: '请输入负责人手机',
},
},
{
fieldName: 'remark',
label: '备注',
component: 'Input',
componentProps: {
placeholder: '请输入备注',
},
},
{
fieldName: 'orderIndex',
label: '显示顺序',
component: 'Input',
componentProps: {
placeholder: '请输入显示顺序',
},
},
{
fieldName: 'whstateScode',
label: '状态',
rules: 'required',
component: 'Select',
componentProps: {
options: getDictOptions(DICT_TYPE.COMMON_STATUS, 'number'),
placeholder: '请选择状态',
allowClear: true,
},
},
{
fieldName: 'isUsed',
label: '是否启用',
rules: 'required',
component: 'RadioGroup',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
buttonStyle: 'solid',
optionType: 'button',
},
},
{
fieldName: 'baseClassId',
label: '物料基本分类',
component: 'Input',
componentProps: {
placeholder: '请输入物料基本分类',
},
},
{
fieldName: 'sysownerid',
label: '拥有者ID',
component: 'Input',
componentProps: {
placeholder: '请输入拥有者ID',
},
},
{
fieldName: 'sysdeptid',
label: '部门ID',
component: 'Input',
componentProps: {
placeholder: '请输入部门ID',
},
},
{
fieldName: 'syscompanyid',
label: '公司ID',
component: 'Input',
componentProps: {
placeholder: '请输入公司ID',
},
},
{
fieldName: 'extId',
label: '外部标识',
component: 'Input',
componentProps: {
placeholder: '请输入外部标识',
},
},
{
fieldName: 'departName',
label: '部门名称',
component: 'Input',
componentProps: {
placeholder: '请输入部门名称',
},
},
{
fieldName: 'companyName',
label: '公司名称',
component: 'Input',
componentProps: {
placeholder: '请输入公司名称',
},
},
];
}
/** 列表的搜索表单 */
export function useGridFormSchema(): VbenFormSchema[] {
return [
{
fieldName: 'storCode',
label: '仓库编码',
component: 'Input',
componentProps: {
allowClear: true,
placeholder: '请输入仓库编码',
},
},
{
fieldName: 'storName',
label: '仓库名称',
component: 'Input',
componentProps: {
allowClear: true,
placeholder: '请输入仓库名称',
},
},
{
fieldName: 'simpleName',
label: '仓库简称',
component: 'Input',
componentProps: {
allowClear: true,
placeholder: '请输入仓库简称',
},
},
{
fieldName: 'storTypeScode',
label: '仓库性质',
component: 'Input',
componentProps: {
allowClear: true,
placeholder: '请输入仓库性质',
},
},
{
fieldName: 'area',
label: '地区',
component: 'Input',
componentProps: {
allowClear: true,
placeholder: '请输入地区',
},
},
{
fieldName: 'isUsed',
label: '是否启用',
component: 'Select',
componentProps: {
options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
placeholder: '请选择是否启用',
allowClear: true,
},
},
{
fieldName: 'createTime',
label: '创建时间',
component: 'RangePicker',
componentProps: {
...getRangePickerDefaultProps(),
allowClear: true,
},
},
];
}
/** 列表的字段 */
export function useGridColumns(): VxeTableGridOptions<WmsBsrealStorAttrApi.BsrealStorAttr>['columns'] {
return [
{ type: 'checkbox', width: 40 },
{
field: 'storCode',
title: '仓库编码',
minWidth: 120,
},
{
field: 'storName',
title: '仓库名称',
minWidth: 120,
},
{
field: 'simpleName',
title: '仓库简称',
minWidth: 120,
},
{
field: 'storCapacity',
title: '仓库容量',
minWidth: 120,
},
{
field: 'totalArea',
title: '总面积',
minWidth: 120,
},
{
field: 'storTypeScode',
title: '仓库性质',
minWidth: 120,
},
{
field: 'isVirtualstore',
title: '是否虚拟库',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'isSemiFinished',
title: '是否半成品库',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'isMaterialstore',
title: '是否原料库',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'isProductstore',
title: '是否成品库',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'isAttachment',
title: '是否备件库',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'isReversed',
title: '是否允许红冲',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'isMvoutAutoCfm',
title: '是否移出业务自动确认',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'isMvinAutoCfm',
title: '是否移入业务自动确认',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'area',
title: '地区',
minWidth: 120,
},
{
field: 'storeaDdress',
title: '仓库地址',
minWidth: 120,
},
{
field: 'principal',
title: '负责人',
minWidth: 120,
},
{
field: 'officePhone',
title: '办公电话',
minWidth: 120,
},
{
field: 'mobileNo',
title: '负责人手机',
minWidth: 120,
},
{
field: 'remark',
title: '备注',
minWidth: 120,
},
{
field: 'orderIndex',
title: '显示顺序',
minWidth: 120,
},
{
field: 'whstateScode',
title: '状态',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.COMMON_STATUS },
},
},
{
field: 'isUsed',
title: '是否启用',
minWidth: 120,
cellRender: {
name: 'CellDict',
props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
},
},
{
field: 'baseClassId',
title: '物料基本分类',
minWidth: 120,
},
{
field: 'createTime',
title: '创建时间',
minWidth: 120,
formatter: 'formatDateTime',
},
{
field: 'sysownerid',
title: '拥有者ID',
minWidth: 120,
},
{
field: 'sysdeptid',
title: '部门ID',
minWidth: 120,
},
{
field: 'syscompanyid',
title: '公司ID',
minWidth: 120,
},
{
field: 'extId',
title: '外部标识',
minWidth: 120,
},
{
field: 'departName',
title: '部门名称',
minWidth: 120,
},
{
field: 'companyName',
title: '公司名称',
minWidth: 120,
},
{
title: '操作',
width: 200,
fixed: 'right',
slots: { default: 'actions' },
},
];
}

View File

@@ -0,0 +1,186 @@
<script lang="ts" setup>
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import type { WmsBsrealStorAttrApi } from '#/api/wms/bsrealstorattr';
import { ref } from 'vue';
import { confirm, Page, useVbenModal } from '@vben/common-ui';
import { downloadFileFromBlobPart, isEmpty } from '@vben/utils';
import { message } from 'antdv-next';
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
import {
deleteBsrealStorAttr,
deleteBsrealStorAttrList,
exportBsrealStorAttr,
getBsrealStorAttrPage,
} from '#/api/wms/bsrealstorattr';
import { $t } from '#/locales';
import { useGridColumns, useGridFormSchema } from './data';
import Form from './modules/form.vue';
const [FormModal, formModalApi] = useVbenModal({
connectedComponent: Form,
destroyOnClose: true,
});
/** 刷新表格 */
function handleRefresh() {
gridApi.query();
}
/** 创建实物库属性 */
function handleCreate() {
formModalApi.setData(null).open();
}
/** 编辑实物库属性 */
function handleEdit(row: WmsBsrealStorAttrApi.BsrealStorAttr) {
formModalApi.setData(row).open();
}
/** 删除实物库属性 */
async function handleDelete(row: WmsBsrealStorAttrApi.BsrealStorAttr) {
const hideLoading = message.loading({
content: $t('ui.actionMessage.deleting', [row.id]),
duration: 0,
});
try {
await deleteBsrealStorAttr(row.id!);
message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
handleRefresh();
} finally {
hideLoading();
}
}
/** 批量删除实物库属性 */
async function handleDeleteBatch() {
await confirm($t('ui.actionMessage.deleteBatchConfirm'));
const hideLoading = message.loading({
content: $t('ui.actionMessage.deletingBatch'),
duration: 0,
});
try {
await deleteBsrealStorAttrList(checkedIds.value);
checkedIds.value = [];
message.success($t('ui.actionMessage.deleteSuccess'));
handleRefresh();
} finally {
hideLoading();
}
}
const checkedIds = ref<number[]>([]);
function handleRowCheckboxChange({
records,
}: {
records: WmsBsrealStorAttrApi.BsrealStorAttr[];
}) {
checkedIds.value = records.map((item) => item.id!);
}
/** 导出表格 */
async function handleExport() {
const data = await exportBsrealStorAttr(await gridApi.formApi.getValues());
downloadFileFromBlobPart({ fileName: '实物库属性.xls', source: data });
}
const [Grid, gridApi] = useVbenVxeGrid({
formOptions: {
schema: useGridFormSchema(),
},
gridOptions: {
columns: useGridColumns(),
height: 'auto',
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getBsrealStorAttrPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
isHover: true,
},
toolbarConfig: {
refresh: true,
search: true,
},
} as VxeTableGridOptions<WmsBsrealStorAttrApi.BsrealStorAttr>,
gridEvents: {
checkboxAll: handleRowCheckboxChange,
checkboxChange: handleRowCheckboxChange,
},
});
</script>
<template>
<Page auto-content-height>
<FormModal @success="handleRefresh" />
<Grid table-title="实物库属性列表">
<template #toolbar-tools>
<TableAction
:actions="[
{
label: $t('ui.actionTitle.create', ['实物库属性']),
type: 'primary',
icon: ACTION_ICON.ADD,
auth: ['wms:bsreal-stor-attr:create'],
onClick: handleCreate,
},
{
label: $t('ui.actionTitle.export'),
type: 'primary',
icon: ACTION_ICON.DOWNLOAD,
auth: ['wms:bsreal-stor-attr:export'],
onClick: handleExport,
},
{
label: $t('ui.actionTitle.deleteBatch'),
type: 'primary',
danger: true,
icon: ACTION_ICON.DELETE,
auth: ['wms:bsreal-stor-attr:delete'],
disabled: isEmpty(checkedIds),
onClick: handleDeleteBatch,
},
]"
/>
</template>
<template #actions="{ row }">
<TableAction
:actions="[
{
label: $t('common.edit'),
type: 'link',
icon: ACTION_ICON.EDIT,
auth: ['wms:bsreal-stor-attr:update'],
onClick: handleEdit.bind(null, row),
},
{
label: $t('common.delete'),
type: 'link',
danger: true,
icon: ACTION_ICON.DELETE,
auth: ['wms:bsreal-stor-attr:delete'],
popConfirm: {
title: $t('ui.actionMessage.deleteConfirm', [row.id]),
confirm: handleDelete.bind(null, row),
},
},
]"
/>
</template>
</Grid>
</Page>
</template>

View File

@@ -0,0 +1,82 @@
<script lang="ts" setup>
import type { WmsBsrealStorAttrApi } from '#/api/wms/bsrealstorattr';
import { computed, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { message } from 'antdv-next';
import { useVbenForm } from '#/adapter/form';
import { createBsrealStorAttr, getBsrealStorAttr, updateBsrealStorAttr } from '#/api/wms/bsrealstorattr';
import { $t } from '#/locales';
import { useFormSchema } from '../data';
const emit = defineEmits(['success']);
const formData = ref<WmsBsrealStorAttrApi.BsrealStorAttr>();
const getTitle = computed(() => {
return formData.value?.id
? $t('ui.actionTitle.edit', ['实物库属性'])
: $t('ui.actionTitle.create', ['实物库属性']);
});
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 80,
},
layout: 'horizontal',
schema: useFormSchema(),
showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
const { valid } = await formApi.validate();
if (!valid) {
return;
}
modalApi.lock();
// 提交表单
const data = (await formApi.getValues()) as WmsBsrealStorAttrApi.BsrealStorAttr;
try {
await (formData.value?.id ? updateBsrealStorAttr(data) : createBsrealStorAttr(data));
// 关闭并提示
await modalApi.close();
emit('success');
message.success($t('ui.actionMessage.operationSuccess'));
} finally {
modalApi.unlock();
}
},
async onOpenChange(isOpen: boolean) {
if (!isOpen) {
formData.value = undefined;
return;
}
// 加载数据
const data = modalApi.getData<WmsBsrealStorAttrApi.BsrealStorAttr>();
if (!data || !data.id) {
return;
}
modalApi.lock();
try {
formData.value = await getBsrealStorAttr(data.id);
// 设置到 values
await formApi.setValues(formData.value);
} finally {
modalApi.unlock();
}
},
});
</script>
<template>
<Modal :title="getTitle">
<Form class="mx-4" />
</Modal>
</template>

View File

@@ -18,6 +18,7 @@
<module>nl-module-infra</module>
<module>nl-module-lms</module>
<module>nl-module-base</module>
<module>nl-module-wms</module>
<module>nl-module-task</module>
<!-- <module>nl-module-member</module>-->
<!-- <module>nl-module-bpm</module>-->