Commit 0742ef17dc417b553065cef15e109f0d5f392178

Authored by YunaiV
1 parent 862b98e7

reactor(infra):增加代码生成的单测(import 情况)

Showing 121 changed files with 9261 additions and 0 deletions

Too many changes.

To preserve performance only 100 of 121 files are displayed.

yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentImportExcelVO",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportExcelVO.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentImportRespVO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportRespVO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentController",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentDO",
  21 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentMapper",
  24 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  25 +}, {
  26 + "contentPath" : "xml/InfraStudentMapper",
  27 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentServiceImpl",
  30 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  31 +}, {
  32 + "contentPath" : "java/InfraStudentService",
  33 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImplTest",
  36 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  37 +}, {
  38 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  39 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  40 +}, {
  41 + "contentPath" : "sql/sql",
  42 + "filePath" : "sql/sql.sql"
  43 +}, {
  44 + "contentPath" : "sql/h2",
  45 + "filePath" : "sql/h2.sql"
  46 +}, {
  47 + "contentPath" : "vue/index",
  48 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  49 +}, {
  50 + "contentPath" : "vue/form",
  51 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  52 +}, {
  53 + "contentPath" : "vue/import-form",
  54 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/import-form.vue"
  55 +}, {
  56 + "contentPath" : "ts/index",
  57 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  58 +} ]
0 59 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/ErrorCodeConstants_手动操作 0 → 100644
  1 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  2 +// ========== 学生 TODO 补充编号 ==========
  3 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
0 4 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import org.springframework.web.multipart.MultipartFile;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.security.access.prepost.PreAuthorize;
  8 +import io.swagger.v3.oas.annotations.tags.Tag;
  9 +import io.swagger.v3.oas.annotations.Parameter;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +
  12 +import jakarta.validation.constraints.*;
  13 +import jakarta.validation.*;
  14 +import jakarta.servlet.http.*;
  15 +import java.util.*;
  16 +import java.io.IOException;
  17 +
  18 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  19 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  20 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  21 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  25 +
  26 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  27 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
  28 +
  29 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  30 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  31 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  32 +
  33 +@Tag(name = "管理后台 - 学生")
  34 +@RestController
  35 +@RequestMapping("/infra/student")
  36 +@Validated
  37 +public class InfraStudentController {
  38 +
  39 + @Resource
  40 + private InfraStudentService studentService;
  41 +
  42 + @PostMapping("/create")
  43 + @Operation(summary = "创建学生")
  44 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  45 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  46 + return success(studentService.createStudent(createReqVO));
  47 + }
  48 +
  49 + @PutMapping("/update")
  50 + @Operation(summary = "更新学生")
  51 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  52 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  53 + studentService.updateStudent(updateReqVO);
  54 + return success(true);
  55 + }
  56 +
  57 + @DeleteMapping("/delete")
  58 + @Operation(summary = "删除学生")
  59 + @Parameter(name = "id", description = "编号", required = true)
  60 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  61 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  62 + studentService.deleteStudent(id);
  63 + return success(true);
  64 + }
  65 +
  66 + @DeleteMapping("/delete-list")
  67 + @Parameter(name = "ids", description = "编号", required = true)
  68 + @Operation(summary = "批量删除学生")
  69 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  70 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  71 + studentService.deleteStudentListByIds(ids);
  72 + return success(true);
  73 + }
  74 +
  75 + @GetMapping("/get")
  76 + @Operation(summary = "获得学生")
  77 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  78 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  79 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  80 + InfraStudentDO student = studentService.getStudent(id);
  81 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  82 + }
  83 +
  84 + @GetMapping("/page")
  85 + @Operation(summary = "获得学生分页")
  86 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  87 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  88 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  89 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  90 + }
  91 +
  92 + @GetMapping("/export-excel")
  93 + @Operation(summary = "导出学生 Excel")
  94 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  95 + @ApiAccessLog(operateType = EXPORT)
  96 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  97 + HttpServletResponse response) throws IOException {
  98 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  99 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  100 + // 导出 Excel
  101 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  102 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  103 + }
  104 +
  105 + @GetMapping("/get-import-template")
  106 + @Operation(summary = "获得导入学生模板")
  107 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  108 + public void importTemplate(HttpServletResponse response) throws IOException {
  109 + ExcelUtils.write(response, "学生导入模板.xls", "数据",
  110 + InfraStudentImportExcelVO.class, Collections.emptyList());
  111 + }
  112 +
  113 + @PostMapping("/import")
  114 + @Operation(summary = "导入学生")
  115 + @Parameter(name = "file", description = "Excel 文件", required = true)
  116 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  117 + public CommonResult<InfraStudentImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
  118 + List<InfraStudentImportExcelVO> list = ExcelUtils.read(file, InfraStudentImportExcelVO.class);
  119 + return success(studentService.importStudentList(list));
  120 + }
  121 +
  122 +}
0 123 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +
  68 +}
0 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentImportExcelVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelProperty;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Builder;
  6 +import lombok.Data;
  7 +import lombok.NoArgsConstructor;
  8 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  9 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  10 +
  11 +/**
  12 + * 学生 Excel 导入 VO
  13 + */
  14 +@Data
  15 +@Builder
  16 +@AllArgsConstructor
  17 +@NoArgsConstructor
  18 +public class InfraStudentImportExcelVO {
  19 +
  20 + @ExcelProperty("名字")
  21 + private String name;
  22 +
  23 + @ExcelProperty("简介")
  24 + private String description;
  25 +
  26 + @ExcelProperty("出生日期")
  27 + private LocalDateTime birthday;
  28 +
  29 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  30 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  31 + private Integer sex;
  32 +
  33 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  34 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  35 + private Boolean enabled;
  36 +
  37 + @ExcelProperty("头像")
  38 + private String avatar;
  39 +
  40 + @ExcelProperty("附件")
  41 + private String video;
  42 +
  43 + @ExcelProperty("备注")
  44 + private String memo;
  45 +
  46 +}
0 47 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentImportRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Map;
  8 +
  9 +@Schema(description = "管理后台 - 学生导入 Response VO")
  10 +@Data
  11 +@Builder
  12 +public class InfraStudentImportRespVO {
  13 +
  14 + @Schema(description = "创建成功的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  15 + private Integer successCount;
  16 +
  17 + @Schema(description = "导入失败的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Integer failureCount;
  19 +
  20 + @Schema(description = "导入失败的数据集合,key 为行号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
  21 + private Map<Integer, String> failureRows;
  22 +
  23 +}
0 24 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +public class InfraStudentPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "名字", example = "芋头")
  17 + private String name;
  18 +
  19 + @Schema(description = "出生日期")
  20 + private LocalDateTime birthday;
  21 +
  22 + @Schema(description = "性别", example = "1")
  23 + private Integer sex;
  24 +
  25 + @Schema(description = "是否有效", example = "true")
  26 + private Boolean enabled;
  27 +
  28 + @Schema(description = "创建时间")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + private LocalDateTime[] createTime;
  31 +
  32 +}
0 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +import java.time.LocalDateTime;
  8 +import cn.idev.excel.annotation.*;
  9 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  10 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  11 +
  12 +@Schema(description = "管理后台 - 学生 Response VO")
  13 +@Data
  14 +@ExcelIgnoreUnannotated
  15 +public class InfraStudentRespVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + @ExcelProperty("编号")
  19 + private Long id;
  20 +
  21 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  22 + @ExcelProperty("名字")
  23 + private String name;
  24 +
  25 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  26 + @ExcelProperty("简介")
  27 + private String description;
  28 +
  29 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  30 + @ExcelProperty("出生日期")
  31 + private LocalDateTime birthday;
  32 +
  33 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  34 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  35 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  36 + private Integer sex;
  37 +
  38 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  39 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  40 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  41 + private Boolean enabled;
  42 +
  43 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  44 + @ExcelProperty("头像")
  45 + private String avatar;
  46 +
  47 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  48 + @ExcelProperty("附件")
  49 + private String video;
  50 +
  51 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  52 + @ExcelProperty("备注")
  53 + private String memo;
  54 +
  55 + @Schema(description = "创建时间")
  56 + @ExcelProperty("创建时间")
  57 + private LocalDateTime createTime;
  58 +
  59 +}
0 60 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import jakarta.validation.constraints.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  11 +@Data
  12 +public class InfraStudentSaveReqVO {
  13 +
  14 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  15 + private Long id;
  16 +
  17 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  18 + @NotEmpty(message = "名字不能为空")
  19 + private String name;
  20 +
  21 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  22 + @NotEmpty(message = "简介不能为空")
  23 + private String description;
  24 +
  25 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  26 + @NotNull(message = "出生日期不能为空")
  27 + private LocalDateTime birthday;
  28 +
  29 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  30 + @NotNull(message = "性别不能为空")
  31 + private Integer sex;
  32 +
  33 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  34 + @NotNull(message = "是否有效不能为空")
  35 + private Boolean enabled;
  36 +
  37 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  38 + @NotEmpty(message = "头像不能为空")
  39 + private String avatar;
  40 +
  41 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  42 + @NotEmpty(message = "附件不能为空")
  43 + private String video;
  44 +
  45 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  46 + @NotEmpty(message = "备注不能为空")
  47 + private String memo;
  48 +
  49 +}
0 50 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import jakarta.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  9 +
  10 +/**
  11 + * 学生 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface InfraStudentService {
  16 +
  17 + /**
  18 + * 创建学生
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 导入学生
  27 + *
  28 + * @param importList 导入信息
  29 + * @return 导入结果
  30 + */
  31 + InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList);
  32 +
  33 + /**
  34 + * 更新学生
  35 + *
  36 + * @param updateReqVO 更新信息
  37 + */
  38 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
  39 +
  40 + /**
  41 + * 删除学生
  42 + *
  43 + * @param id 编号
  44 + */
  45 + void deleteStudent(Long id);
  46 +
  47 + /**
  48 + * 批量删除学生
  49 + *
  50 + * @param ids 编号
  51 + */
  52 + void deleteStudentListByIds(List<Long> ids);
  53 +
  54 + /**
  55 + * 获得学生
  56 + *
  57 + * @param id 编号
  58 + * @return 学生
  59 + */
  60 + InfraStudentDO getStudent(Long id);
  61 +
  62 + /**
  63 + * 获得学生分页
  64 + *
  65 + * @param pageReqVO 分页查询
  66 + * @return 学生分页
  67 + */
  68 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  69 +
  70 +}
0 71 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import org.springframework.stereotype.Service;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.transaction.annotation.Transactional;
  8 +
  9 +import java.util.*;
  10 +import java.util.concurrent.atomic.AtomicInteger;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  15 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  16 +
  17 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class InfraStudentServiceImpl implements InfraStudentService {
  32 +
  33 + @Resource
  34 + private InfraStudentMapper studentMapper;
  35 +
  36 + @Override
  37 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  38 + // 插入
  39 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  40 + studentMapper.insert(student);
  41 +
  42 + // 返回
  43 + return student.getId();
  44 + }
  45 +
  46 + @Override
  47 + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入
  48 + public InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList) {
  49 + if (CollUtil.isEmpty(importList)) {
  50 + return InfraStudentImportRespVO.builder()
  51 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  52 + }
  53 + // 遍历,逐个创建
  54 + InfraStudentImportRespVO respVO = InfraStudentImportRespVO.builder()
  55 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  56 + AtomicInteger index = new AtomicInteger(1);
  57 + importList.forEach(importItem -> {
  58 + int currentIndex = index.getAndIncrement();
  59 + try {
  60 + createStudent(BeanUtils.toBean(importItem, InfraStudentSaveReqVO.class));
  61 + respVO.setSuccessCount(respVO.getSuccessCount() + 1);
  62 + } catch (Exception ex) {
  63 + respVO.getFailureRows().put(currentIndex, ex.getMessage());
  64 + }
  65 + });
  66 + respVO.setFailureCount(respVO.getFailureRows().size());
  67 + return respVO;
  68 + }
  69 +
  70 + @Override
  71 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  72 + // 校验存在
  73 + validateStudentExists(updateReqVO.getId());
  74 + // 更新
  75 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  76 + studentMapper.updateById(updateObj);
  77 + }
  78 +
  79 + @Override
  80 + public void deleteStudent(Long id) {
  81 + // 校验存在
  82 + validateStudentExists(id);
  83 + // 删除
  84 + studentMapper.deleteById(id);
  85 + }
  86 +
  87 + @Override
  88 + public void deleteStudentListByIds(List<Long> ids) {
  89 + // 删除
  90 + studentMapper.deleteByIds(ids);
  91 + }
  92 +
  93 +
  94 + private void validateStudentExists(Long id) {
  95 + if (studentMapper.selectById(id) == null) {
  96 + throw exception(STUDENT_NOT_EXISTS);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public InfraStudentDO getStudent(Long id) {
  102 + return studentMapper.selectById(id);
  103 + }
  104 +
  105 + @Override
  106 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  107 + return studentMapper.selectPage(pageReqVO);
  108 + }
  109 +
  110 +}
0 111 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +
  6 +import jakarta.annotation.Resource;
  7 +
  8 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  9 +
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  12 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +
  15 +import jakarta.annotation.Resource;
  16 +import org.springframework.context.annotation.Import;
  17 +import java.util.*;
  18 +import java.time.LocalDateTime;
  19 +
  20 +import static cn.hutool.core.util.RandomUtil.*;
  21 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  22 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  27 +import static org.junit.jupiter.api.Assertions.*;
  28 +import static org.mockito.Mockito.*;
  29 +
  30 +/**
  31 + * {@link InfraStudentServiceImpl} 的单元测试类
  32 + *
  33 + * @author 芋道源码
  34 + */
  35 +@Import(InfraStudentServiceImpl.class)
  36 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  37 +
  38 + @Resource
  39 + private InfraStudentServiceImpl studentService;
  40 +
  41 + @Resource
  42 + private InfraStudentMapper studentMapper;
  43 +
  44 + @Test
  45 + public void testCreateStudent_success() {
  46 + // 准备参数
  47 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  48 +
  49 + // 调用
  50 + Long studentId = studentService.createStudent(createReqVO);
  51 + // 断言
  52 + assertNotNull(studentId);
  53 + // 校验记录的属性是否正确
  54 + InfraStudentDO student = studentMapper.selectById(studentId);
  55 + assertPojoEquals(createReqVO, student, "id");
  56 + }
  57 +
  58 + @Test
  59 + public void testUpdateStudent_success() {
  60 + // mock 数据
  61 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  62 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  63 + // 准备参数
  64 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  65 + o.setId(dbStudent.getId()); // 设置更新的 ID
  66 + });
  67 +
  68 + // 调用
  69 + studentService.updateStudent(updateReqVO);
  70 + // 校验是否更新正确
  71 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  72 + assertPojoEquals(updateReqVO, student);
  73 + }
  74 +
  75 + @Test
  76 + public void testUpdateStudent_notExists() {
  77 + // 准备参数
  78 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  79 +
  80 + // 调用, 并断言异常
  81 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  82 + }
  83 +
  84 + @Test
  85 + public void testDeleteStudent_success() {
  86 + // mock 数据
  87 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  88 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  89 + // 准备参数
  90 + Long id = dbStudent.getId();
  91 +
  92 + // 调用
  93 + studentService.deleteStudent(id);
  94 + // 校验数据不存在了
  95 + assertNull(studentMapper.selectById(id));
  96 + }
  97 +
  98 + @Test
  99 + public void testDeleteStudent_notExists() {
  100 + // 准备参数
  101 + Long id = randomLongId();
  102 +
  103 + // 调用, 并断言异常
  104 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  105 + }
  106 +
  107 + @Test
  108 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  109 + public void testGetStudentPage() {
  110 + // mock 数据
  111 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  112 + o.setName(null);
  113 + o.setBirthday(null);
  114 + o.setSex(null);
  115 + o.setEnabled(null);
  116 + o.setCreateTime(null);
  117 + });
  118 + studentMapper.insert(dbStudent);
  119 + // 测试 name 不匹配
  120 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  121 + // 测试 birthday 不匹配
  122 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  123 + // 测试 sex 不匹配
  124 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  125 + // 测试 enabled 不匹配
  126 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  127 + // 测试 createTime 不匹配
  128 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  129 + // 准备参数
  130 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  131 + reqVO.setName(null);
  132 + reqVO.setBirthday(null);
  133 + reqVO.setSex(null);
  134 + reqVO.setEnabled(null);
  135 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  136 +
  137 + // 调用
  138 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  139 + // 断言
  140 + assertEquals(1, pageResult.getTotal());
  141 + assertEquals(1, pageResult.getList().size());
  142 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  143 + }
  144 +
  145 +}
0 146 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +SELECT @parentId := LAST_INSERT_ID();
  13 +
  14 +-- 按钮 SQL
  15 +INSERT INTO system_menu(
  16 + name, permission, type, sort, parent_id,
  17 + path, icon, component, status
  18 +)
  19 +VALUES (
  20 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  21 + '', '', '', 0
  22 +);
  23 +INSERT INTO system_menu(
  24 + name, permission, type, sort, parent_id,
  25 + path, icon, component, status
  26 +)
  27 +VALUES (
  28 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  29 + '', '', '', 0
  30 +);
  31 +INSERT INTO system_menu(
  32 + name, permission, type, sort, parent_id,
  33 + path, icon, component, status
  34 +)
  35 +VALUES (
  36 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  37 + '', '', '', 0
  38 +);
  39 +INSERT INTO system_menu(
  40 + name, permission, type, sort, parent_id,
  41 + path, icon, component, status
  42 +)
  43 +VALUES (
  44 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  45 + '', '', '', 0
  46 +);
  47 +INSERT INTO system_menu(
  48 + name, permission, type, sort, parent_id,
  49 + path, icon, component, status
  50 +)
  51 +VALUES (
  52 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  53 + '', '', '', 0
  54 +);
  55 +INSERT INTO system_menu(
  56 + name, permission, type, sort, parent_id,
  57 + path, icon, component, status
  58 +)
  59 +VALUES (
  60 + '学生导入', 'infra:student:import', 3, 6, @parentId,
  61 + '', '', '', 0
  62 +);
0 63 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/ts/index 0 → 100644
  1 +import type { PageParam, PageResult } from '@vben/request';
  2 +import type { Dayjs } from 'dayjs';
  3 +
  4 +import { requestClient } from '#/api/request';
  5 +
  6 +export namespace StudentApi {
  7 + /** 学生信息 */
  8 + export interface Student {
  9 + id: number; // 编号
  10 + name?: string; // 名字
  11 + description?: string; // 简介
  12 + birthday?: string | Dayjs; // 出生日期
  13 + sex?: number; // 性别
  14 + enabled?: boolean; // 是否有效
  15 + avatar?: string; // 头像
  16 + video?: string; // 附件
  17 + memo?: string; // 备注
  18 + }
  19 +}
  20 +
  21 +/** 查询学生分页 */
  22 +export function getStudentPage(params: PageParam) {
  23 + return requestClient.get<PageResult<StudentApi.Student>>('/infra/student/page', { params });
  24 +}
  25 +
  26 +/** 查询学生详情 */
  27 +export function getStudent(id: number) {
  28 + return requestClient.get<StudentApi.Student>(`/infra/student/get?id=${id}`);
  29 +}
  30 +
  31 +/** 新增学生 */
  32 +export function createStudent(data: StudentApi.Student) {
  33 + return requestClient.post('/infra/student/create', data);
  34 +}
  35 +
  36 +/** 修改学生 */
  37 +export function updateStudent(data: StudentApi.Student) {
  38 + return requestClient.put('/infra/student/update', data);
  39 +}
  40 +
  41 +/** 删除学生 */
  42 +export function deleteStudent(id: number) {
  43 + return requestClient.delete(`/infra/student/delete?id=${id}`);
  44 +}
  45 +
  46 +/** 批量删除学生 */
  47 +export function deleteStudentList(ids: number[]) {
  48 + return requestClient.delete(`/infra/student/delete-list?ids=${ids.join(',')}`)
  49 +}
  50 +
  51 +/** 导出学生 */
  52 +export function exportStudent(params: any) {
  53 + return requestClient.download('/infra/student/export-excel', { params });
  54 +}
  55 +
  56 +/** 下载学生导入模板 */
  57 +export function importStudentTemplate() {
  58 + return requestClient.download('/infra/student/get-import-template');
  59 +}
  60 +
  61 +/** 导入学生 */
  62 +export function importStudent(data: FormData) {
  63 + return requestClient.post('/infra/student/import', data);
  64 +}
0 65 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/vue/form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { Rule } from 'ant-design-vue/es/form';
  3 +import type { StudentApi } from '#/api/infra/demo';
  4 +
  5 +import { computed, ref } from 'vue';
  6 +
  7 +import { useVbenModal } from '@vben/common-ui';
  8 +import { DICT_TYPE } from '@vben/constants';
  9 +import { getDictOptions } from '@vben/hooks';
  10 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  11 +import { ImageUpload, FileUpload } from "#/components/upload";
  12 +import { message, Tabs, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'ant-design-vue';
  13 +
  14 +import { $t } from '#/locales';
  15 +import { getStudent, createStudent, updateStudent } from '#/api/infra/demo';
  16 +
  17 +const emit = defineEmits(['success']);
  18 +
  19 +const formRef = ref();
  20 +const formData = ref<Partial<StudentApi.Student>>({
  21 + id: undefined,
  22 + name: undefined,
  23 + description: undefined,
  24 + birthday: undefined,
  25 + sex: undefined,
  26 + enabled: undefined,
  27 + avatar: undefined,
  28 + video: undefined,
  29 + memo: undefined,
  30 +});
  31 +const rules: Record<string, Rule[]> = {
  32 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  33 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  34 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  35 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  36 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  37 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  38 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  39 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  40 +};
  41 +const getTitle = computed(() => {
  42 + return formData.value?.id
  43 + ? $t('ui.actionTitle.edit', ['学生'])
  44 + : $t('ui.actionTitle.create', ['学生']);
  45 +});
  46 +
  47 +
  48 +/** 重置表单 */
  49 +function resetForm() {
  50 + formData.value = {
  51 + id: undefined,
  52 + name: undefined,
  53 + description: undefined,
  54 + birthday: undefined,
  55 + sex: undefined,
  56 + enabled: undefined,
  57 + avatar: undefined,
  58 + video: undefined,
  59 + memo: undefined,
  60 + };
  61 + formRef.value?.resetFields();
  62 +}
  63 +
  64 +
  65 +const [Modal, modalApi] = useVbenModal({
  66 + async onConfirm() {
  67 + await formRef.value?.validate();
  68 + modalApi.lock();
  69 + // 提交表单
  70 + const data = formData.value as StudentApi.Student;
  71 + try {
  72 + await (formData.value?.id ? updateStudent(data) : createStudent(data));
  73 + // 关闭并提示
  74 + await modalApi.close();
  75 + emit('success');
  76 + message.success({
  77 + content: $t('ui.actionMessage.operationSuccess'),
  78 + });
  79 + } finally {
  80 + modalApi.unlock();
  81 + }
  82 + },
  83 + async onOpenChange(isOpen: boolean) {
  84 + if (!isOpen) {
  85 + resetForm()
  86 + return;
  87 + }
  88 + // 加载数据
  89 + let data = modalApi.getData<StudentApi.Student>();
  90 + if (!data) {
  91 + return;
  92 + }
  93 + if (data.id) {
  94 + modalApi.lock();
  95 + try {
  96 + data = await getStudent(data.id);
  97 + } finally {
  98 + modalApi.unlock();
  99 + }
  100 + }
  101 + formData.value = data;
  102 + },
  103 +});
  104 +</script>
  105 +
  106 +<template>
  107 + <Modal :title="getTitle">
  108 + <Form
  109 + ref="formRef"
  110 + :model="formData"
  111 + :rules="rules"
  112 + :label-col="{ span: 5 }"
  113 + :wrapper-col="{ span: 18 }"
  114 + >
  115 + <Form.Item label="名字" name="name">
  116 + <Input v-model:value="formData.name" placeholder="请输入名字" />
  117 + </Form.Item>
  118 + <Form.Item label="简介" name="description">
  119 + <Textarea v-model:value="formData.description" placeholder="请输入简介" />
  120 + </Form.Item>
  121 + <Form.Item label="出生日期" name="birthday">
  122 + <DatePicker
  123 + v-model:value="formData.birthday"
  124 + valueFormat="x"
  125 + placeholder="选择出生日期"
  126 + />
  127 + </Form.Item>
  128 + <Form.Item label="性别" name="sex">
  129 + <Select v-model:value="formData.sex" placeholder="请选择性别">
  130 + <Select.Option
  131 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  132 + :key="dict.value"
  133 + :value="dict.value"
  134 + >
  135 + {{ dict.label }}
  136 + </Select.Option>
  137 + </Select>
  138 + </Form.Item>
  139 + <Form.Item label="是否有效" name="enabled">
  140 + <RadioGroup v-model:value="formData.enabled">
  141 + <Radio
  142 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  143 + :key="dict.value"
  144 + :value="dict.value"
  145 + >
  146 + {{ dict.label }}
  147 + </Radio>
  148 + </RadioGroup>
  149 + </Form.Item>
  150 + <Form.Item label="头像" name="avatar">
  151 + <ImageUpload v-model:value="formData.avatar" />
  152 + </Form.Item>
  153 + <Form.Item label="附件" name="video">
  154 + <FileUpload v-model:value="formData.video" />
  155 + </Form.Item>
  156 + <Form.Item label="备注" name="memo">
  157 + <RichTextarea v-model="formData.memo" height="500px" />
  158 + </Form.Item>
  159 + </Form>
  160 + </Modal>
  161 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/vue/import-form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { FileType } from 'ant-design-vue/es/upload/interface';
  3 +
  4 +import { ref } from 'vue';
  5 +
  6 +import { useVbenModal } from '@vben/common-ui';
  7 +import { downloadFileFromBlobPart } from '@vben/utils';
  8 +
  9 +import { Button, message, Upload } from 'ant-design-vue';
  10 +
  11 +import { importStudent, importStudentTemplate } from '#/api/infra/demo';
  12 +
  13 +defineOptions({ name: 'StudentImport' });
  14 +
  15 +const emit = defineEmits(['success']);
  16 +const fileRef = ref<File | null>(null);
  17 +
  18 +const [Modal, modalApi] = useVbenModal({
  19 + async onConfirm() {
  20 + if (!fileRef.value) {
  21 + message.error('请上传文件');
  22 + return;
  23 + }
  24 + modalApi.lock();
  25 + try {
  26 + const formData = new FormData();
  27 + formData.append('file', fileRef.value);
  28 + const response: any = await importStudent(formData);
  29 + const data = response?.data ?? response ?? {};
  30 + let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';';
  31 + if (data.failureRows) {
  32 + Object.keys(data.failureRows).forEach((rowNo) => {
  33 + text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >';
  34 + });
  35 + }
  36 + message.info(text);
  37 + await modalApi.close();
  38 + emit('success');
  39 + } finally {
  40 + modalApi.unlock();
  41 + }
  42 + },
  43 +});
  44 +
  45 +/** 上传前:拦截 antd Upload 的自动上传,文件存到 ref */
  46 +function beforeUpload(file: FileType) {
  47 + fileRef.value = file as unknown as File;
  48 + return false;
  49 +}
  50 +
  51 +/** 下载导入模板 */
  52 +async function handleDownload() {
  53 + const data = await importStudentTemplate();
  54 + downloadFileFromBlobPart({ fileName: '学生导入模板.xls', source: data });
  55 +}
  56 +</script>
  57 +
  58 +<template>
  59 + <Modal title="导入学生" class="w-1/3">
  60 + <div class="mx-4">
  61 + <Upload :max-count="1" accept=".xls,.xlsx" :before-upload="beforeUpload">
  62 + <Button type="primary"> 选择 Excel 文件 </Button>
  63 + </Upload>
  64 + </div>
  65 + <template #prepend-footer>
  66 + <div class="flex flex-auto items-center">
  67 + <Button @click="handleDownload"> 下载导入模板 </Button>
  68 + </div>
  69 + </template>
  70 + </Modal>
  71 +</template>
0 72 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/vue/index 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +
  4 +import { ref, h, reactive, onMounted, nextTick } from 'vue';
  5 +
  6 +import { Page, useVbenModal } from '@vben/common-ui';
  7 +import { DICT_TYPE } from '@vben/constants';
  8 +import { getDictOptions } from '@vben/hooks';
  9 +import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table';
  10 +import { cloneDeep, downloadFileFromBlobPart, formatDateTime, isEmpty } from '@vben/utils';
  11 +import { Button, Card, message, Tabs, Pagination, Form, RangePicker, DatePicker, Select, Input } from 'ant-design-vue';
  12 +import StudentForm from './modules/form.vue';
  13 +import { Download, Plus, RefreshCw, Search, Trash2 } from '@vben/icons';
  14 +import { DictTag } from '#/components/dict-tag';
  15 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  16 +import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
  17 +
  18 +
  19 +import { $t } from '#/locales';
  20 +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/demo';
  21 +import StudentImport from './modules/import-form.vue';
  22 +
  23 +
  24 +const loading = ref(true) // 列表的加载中
  25 +const list = ref<StudentApi.Student[]>([]) // 列表的数据
  26 +
  27 +const total = ref(0) // 列表的总页数
  28 +const queryParams = reactive({
  29 + pageNo: 1,
  30 + pageSize: 10,
  31 + name: undefined,
  32 + birthday: undefined,
  33 + birthday: undefined,
  34 + sex: undefined,
  35 + enabled: undefined,
  36 + createTime: undefined,
  37 +})
  38 +const queryFormRef = ref() // 搜索的表单
  39 +const exportLoading = ref(false) // 导出的加载中
  40 +
  41 +/** 查询列表 */
  42 +async function getList() {
  43 + loading.value = true
  44 + try {
  45 + const params = cloneDeep(queryParams) as any;
  46 + if (params.birthday && Array.isArray(params.birthday)) {
  47 + params.birthday = (params.birthday as string[]).join(',');
  48 + }
  49 + if (params.createTime && Array.isArray(params.createTime)) {
  50 + params.createTime = (params.createTime as string[]).join(',');
  51 + }
  52 + const data = await getStudentPage(params)
  53 + list.value = data.list
  54 + total.value = data.total
  55 + } finally {
  56 + loading.value = false
  57 + }
  58 +}
  59 +
  60 +/** 搜索按钮操作 */
  61 +function handleQuery() {
  62 + queryParams.pageNo = 1
  63 + getList()
  64 +}
  65 +
  66 +/** 重置按钮操作 */
  67 +function resetQuery() {
  68 + queryFormRef.value.resetFields()
  69 + handleQuery()
  70 +}
  71 +
  72 +const [FormModal, formModalApi] = useVbenModal({
  73 + connectedComponent: StudentForm,
  74 + destroyOnClose: true,
  75 +});
  76 +const [ImportFormModal, importFormModalApi] = useVbenModal({
  77 + connectedComponent: StudentImport,
  78 + destroyOnClose: true,
  79 +});
  80 +
  81 +/** 导入学生 */
  82 +function handleImport() {
  83 + importFormModalApi.open();
  84 +}
  85 +
  86 +/** 创建学生 */
  87 +function handleCreate() {
  88 + formModalApi.setData(null).open();
  89 +}
  90 +
  91 +/** 编辑学生 */
  92 +function handleEdit(row: StudentApi.Student) {
  93 + formModalApi.setData(row).open();
  94 +}
  95 +
  96 +
  97 +/** 删除学生 */
  98 +async function handleDelete(row: StudentApi.Student) {
  99 + const hideLoading = message.loading({
  100 + content: $t('ui.actionMessage.deleting', [row.id]),
  101 + duration: 0,
  102 + });
  103 + try {
  104 + await deleteStudent(row.id!);
  105 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  106 + await getList();
  107 + } finally {
  108 + hideLoading();
  109 + }
  110 +}
  111 +
  112 +/** 批量删除学生 */
  113 +async function handleDeleteBatch() {
  114 + const hideLoading = message.loading({
  115 + content: $t('ui.actionMessage.deleting'),
  116 + duration: 0,
  117 + });
  118 + try {
  119 + await deleteStudentList(checkedIds.value);
  120 + checkedIds.value = [];
  121 + message.success($t('ui.actionMessage.deleteSuccess'));
  122 + await getList();
  123 + } finally {
  124 + hideLoading();
  125 + }
  126 +}
  127 +
  128 +const checkedIds = ref<number[]>([])
  129 +function handleRowCheckboxChange({
  130 + records,
  131 +}: {
  132 + records: StudentApi.Student[];
  133 +}) {
  134 + checkedIds.value = records.map((item) => item.id!);
  135 +}
  136 +
  137 +/** 导出表格 */
  138 +async function handleExport() {
  139 +try {
  140 + exportLoading.value = true;
  141 + const data = await exportStudent(queryParams);
  142 + downloadFileFromBlobPart({ fileName: '学生.xls', source: data });
  143 +}finally {
  144 + exportLoading.value = false;
  145 +}
  146 +}
  147 +
  148 +
  149 +
  150 +/** 初始化 */
  151 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  152 +onMounted(() => {
  153 + getList();
  154 +});
  155 +</script>
  156 +
  157 +<template>
  158 + <Page auto-content-height>
  159 + <FormModal @success="getList" />
  160 + <ImportFormModal @success="getList" />
  161 +
  162 + <Card v-if="!hiddenSearchBar" class="mb-4">
  163 + <!-- 搜索工作栏 -->
  164 + <Form
  165 + :model="queryParams"
  166 + ref="queryFormRef"
  167 + layout="inline"
  168 + >
  169 + <Form.Item label="名字" name="name">
  170 + <Input
  171 + v-model:value="queryParams.name"
  172 + placeholder="请输入名字"
  173 + allowClear
  174 + @pressEnter="handleQuery"
  175 + class="w-full"
  176 + />
  177 + </Form.Item>
  178 + <Form.Item label="出生日期" name="birthday">
  179 + <DatePicker
  180 + v-model:value="queryParams.birthday"
  181 + valueFormat="YYYY-MM-DD"
  182 + placeholder="选择出生日期"
  183 + allowClear
  184 + class="w-full"
  185 + />
  186 + </Form.Item>
  187 + <Form.Item label="性别" name="sex">
  188 + <Select
  189 + v-model:value="queryParams.sex"
  190 + placeholder="请选择性别"
  191 + allowClear
  192 + class="w-full"
  193 + >
  194 + <Select.Option
  195 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  196 + :key="dict.value"
  197 + :value="dict.value"
  198 + >
  199 + {{ dict.label }}
  200 + </Select.Option>
  201 + </Select>
  202 + </Form.Item>
  203 + <Form.Item label="是否有效" name="enabled">
  204 + <Select
  205 + v-model:value="queryParams.enabled"
  206 + placeholder="请选择是否有效"
  207 + allowClear
  208 + class="w-full"
  209 + >
  210 + <Select.Option
  211 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  212 + :key="dict.value"
  213 + :value="dict.value"
  214 + >
  215 + {{ dict.label }}
  216 + </Select.Option>
  217 + </Select>
  218 + </Form.Item>
  219 + <Form.Item label="创建时间" name="createTime">
  220 + <RangePicker
  221 + v-model:value="queryParams.createTime"
  222 + v-bind="getRangePickerDefaultProps()"
  223 + class="w-full"
  224 + />
  225 + </Form.Item>
  226 + <Form.Item>
  227 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  228 + <Button class="ml-2" @click="handleQuery" type="primary">
  229 + 搜索
  230 + </Button>
  231 + </Form.Item>
  232 + </Form>
  233 + </Card>
  234 +
  235 + <!-- 列表 -->
  236 + <Card title="学生">
  237 + <template #extra>
  238 + <VbenVxeTableToolbar
  239 + ref="tableToolbarRef"
  240 + v-model:hidden-search="hiddenSearchBar"
  241 + >
  242 + <Button
  243 + class="ml-2"
  244 + :icon="h(Plus)"
  245 + type="primary"
  246 + @click="handleCreate"
  247 + v-access:code="['infra:student:create']"
  248 + >
  249 + {{ $t('ui.actionTitle.create', ['学生']) }}
  250 + </Button>
  251 + <Button
  252 + class="ml-2"
  253 + type="primary"
  254 + @click="handleImport"
  255 + v-access:code="['infra:student:import']"
  256 + >
  257 + 导入
  258 + </Button>
  259 + <Button
  260 + :icon="h(Download)"
  261 + type="primary"
  262 + class="ml-2"
  263 + :loading="exportLoading"
  264 + @click="handleExport"
  265 + v-access:code="['infra:student:export']"
  266 + >
  267 + {{ $t('ui.actionTitle.export') }}
  268 + </Button>
  269 + <Button
  270 + :icon="h(Trash2)"
  271 + type="primary"
  272 + danger
  273 + class="ml-2"
  274 + :disabled="isEmpty(checkedIds)"
  275 + @click="handleDeleteBatch"
  276 + v-access:code="['infra:student:delete']"
  277 + >
  278 + 批量删除
  279 + </Button>
  280 + </VbenVxeTableToolbar>
  281 + </template>
  282 + <VxeTable
  283 + ref="tableRef"
  284 + :data="list"
  285 + show-overflow
  286 + :loading="loading"
  287 + @checkboxAll="handleRowCheckboxChange"
  288 + @checkboxChange="handleRowCheckboxChange"
  289 + >
  290 + <VxeColumn type="checkbox" width="40" />
  291 + <VxeColumn field="id" title="编号" align="center" />
  292 + <VxeColumn field="name" title="名字" align="center" />
  293 + <VxeColumn field="description" title="简介" align="center" />
  294 + <VxeColumn field="birthday" title="出生日期" align="center">
  295 + <template #default="{row}">
  296 + {{formatDateTime(row.birthday)}}
  297 + </template>
  298 + </VxeColumn>
  299 + <VxeColumn field="sex" title="性别" align="center">
  300 + <template #default="{row}">
  301 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  302 + </template>
  303 + </VxeColumn>
  304 + <VxeColumn field="enabled" title="是否有效" align="center">
  305 + <template #default="{row}">
  306 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  307 + </template>
  308 + </VxeColumn>
  309 + <VxeColumn field="avatar" title="头像" align="center" />
  310 + <VxeColumn field="video" title="附件" align="center" />
  311 + <VxeColumn field="memo" title="备注" align="center" />
  312 + <VxeColumn field="createTime" title="创建时间" align="center">
  313 + <template #default="{row}">
  314 + {{formatDateTime(row.createTime)}}
  315 + </template>
  316 + </VxeColumn>
  317 + <VxeColumn field="operation" title="操作" align="center">
  318 + <template #default="{row}">
  319 + <Button
  320 + size="small"
  321 + type="link"
  322 + @click="handleEdit(row)"
  323 + v-access:code="['infra:student:update']"
  324 + >
  325 + {{ $t('ui.actionTitle.edit') }}
  326 + </Button>
  327 + <Button
  328 + size="small"
  329 + type="link"
  330 + danger
  331 + class="ml-2"
  332 + @click="handleDelete(row)"
  333 + v-access:code="['infra:student:delete']"
  334 + >
  335 + {{ $t('ui.actionTitle.delete') }}
  336 + </Button>
  337 + </template>
  338 + </VxeColumn>
  339 + </VxeTable>
  340 + <!-- 分页 -->
  341 + <div class="mt-2 flex justify-end">
  342 + <Pagination
  343 + :total="total"
  344 + v-model:current="queryParams.pageNo"
  345 + v-model:page-size="queryParams.pageSize"
  346 + show-size-changer
  347 + @change="getList"
  348 + />
  349 + </div>
  350 + </Card>
  351 + </Page>
  352 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/xml/InfraStudentMapper 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentImportExcelVO",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportExcelVO.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentImportRespVO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportRespVO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentController",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentDO",
  21 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentMapper",
  24 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  25 +}, {
  26 + "contentPath" : "xml/InfraStudentMapper",
  27 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentServiceImpl",
  30 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  31 +}, {
  32 + "contentPath" : "java/InfraStudentService",
  33 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImplTest",
  36 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  37 +}, {
  38 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  39 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  40 +}, {
  41 + "contentPath" : "sql/sql",
  42 + "filePath" : "sql/sql.sql"
  43 +}, {
  44 + "contentPath" : "sql/h2",
  45 + "filePath" : "sql/h2.sql"
  46 +}, {
  47 + "contentPath" : "ts/data",
  48 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/data.ts"
  49 +}, {
  50 + "contentPath" : "vue/index",
  51 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  52 +}, {
  53 + "contentPath" : "vue/form",
  54 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  55 +}, {
  56 + "contentPath" : "vue/import-form",
  57 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/import-form.vue"
  58 +}, {
  59 + "contentPath" : "ts/index",
  60 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  61 +} ]
0 62 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/ErrorCodeConstants_手动操作 0 → 100644
  1 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  2 +// ========== 学生 TODO 补充编号 ==========
  3 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
0 4 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import org.springframework.web.multipart.MultipartFile;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.security.access.prepost.PreAuthorize;
  8 +import io.swagger.v3.oas.annotations.tags.Tag;
  9 +import io.swagger.v3.oas.annotations.Parameter;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +
  12 +import jakarta.validation.constraints.*;
  13 +import jakarta.validation.*;
  14 +import jakarta.servlet.http.*;
  15 +import java.util.*;
  16 +import java.io.IOException;
  17 +
  18 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  19 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  20 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  21 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  25 +
  26 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  27 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
  28 +
  29 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  30 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  31 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  32 +
  33 +@Tag(name = "管理后台 - 学生")
  34 +@RestController
  35 +@RequestMapping("/infra/student")
  36 +@Validated
  37 +public class InfraStudentController {
  38 +
  39 + @Resource
  40 + private InfraStudentService studentService;
  41 +
  42 + @PostMapping("/create")
  43 + @Operation(summary = "创建学生")
  44 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  45 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  46 + return success(studentService.createStudent(createReqVO));
  47 + }
  48 +
  49 + @PutMapping("/update")
  50 + @Operation(summary = "更新学生")
  51 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  52 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  53 + studentService.updateStudent(updateReqVO);
  54 + return success(true);
  55 + }
  56 +
  57 + @DeleteMapping("/delete")
  58 + @Operation(summary = "删除学生")
  59 + @Parameter(name = "id", description = "编号", required = true)
  60 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  61 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  62 + studentService.deleteStudent(id);
  63 + return success(true);
  64 + }
  65 +
  66 + @DeleteMapping("/delete-list")
  67 + @Parameter(name = "ids", description = "编号", required = true)
  68 + @Operation(summary = "批量删除学生")
  69 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  70 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  71 + studentService.deleteStudentListByIds(ids);
  72 + return success(true);
  73 + }
  74 +
  75 + @GetMapping("/get")
  76 + @Operation(summary = "获得学生")
  77 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  78 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  79 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  80 + InfraStudentDO student = studentService.getStudent(id);
  81 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  82 + }
  83 +
  84 + @GetMapping("/page")
  85 + @Operation(summary = "获得学生分页")
  86 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  87 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  88 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  89 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  90 + }
  91 +
  92 + @GetMapping("/export-excel")
  93 + @Operation(summary = "导出学生 Excel")
  94 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  95 + @ApiAccessLog(operateType = EXPORT)
  96 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  97 + HttpServletResponse response) throws IOException {
  98 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  99 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  100 + // 导出 Excel
  101 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  102 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  103 + }
  104 +
  105 + @GetMapping("/get-import-template")
  106 + @Operation(summary = "获得导入学生模板")
  107 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  108 + public void importTemplate(HttpServletResponse response) throws IOException {
  109 + ExcelUtils.write(response, "学生导入模板.xls", "数据",
  110 + InfraStudentImportExcelVO.class, Collections.emptyList());
  111 + }
  112 +
  113 + @PostMapping("/import")
  114 + @Operation(summary = "导入学生")
  115 + @Parameter(name = "file", description = "Excel 文件", required = true)
  116 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  117 + public CommonResult<InfraStudentImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
  118 + List<InfraStudentImportExcelVO> list = ExcelUtils.read(file, InfraStudentImportExcelVO.class);
  119 + return success(studentService.importStudentList(list));
  120 + }
  121 +
  122 +}
0 123 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +
  68 +}
0 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentImportExcelVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelProperty;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Builder;
  6 +import lombok.Data;
  7 +import lombok.NoArgsConstructor;
  8 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  9 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  10 +
  11 +/**
  12 + * 学生 Excel 导入 VO
  13 + */
  14 +@Data
  15 +@Builder
  16 +@AllArgsConstructor
  17 +@NoArgsConstructor
  18 +public class InfraStudentImportExcelVO {
  19 +
  20 + @ExcelProperty("名字")
  21 + private String name;
  22 +
  23 + @ExcelProperty("简介")
  24 + private String description;
  25 +
  26 + @ExcelProperty("出生日期")
  27 + private LocalDateTime birthday;
  28 +
  29 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  30 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  31 + private Integer sex;
  32 +
  33 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  34 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  35 + private Boolean enabled;
  36 +
  37 + @ExcelProperty("头像")
  38 + private String avatar;
  39 +
  40 + @ExcelProperty("附件")
  41 + private String video;
  42 +
  43 + @ExcelProperty("备注")
  44 + private String memo;
  45 +
  46 +}
0 47 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentImportRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Map;
  8 +
  9 +@Schema(description = "管理后台 - 学生导入 Response VO")
  10 +@Data
  11 +@Builder
  12 +public class InfraStudentImportRespVO {
  13 +
  14 + @Schema(description = "创建成功的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  15 + private Integer successCount;
  16 +
  17 + @Schema(description = "导入失败的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Integer failureCount;
  19 +
  20 + @Schema(description = "导入失败的数据集合,key 为行号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
  21 + private Map<Integer, String> failureRows;
  22 +
  23 +}
0 24 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +public class InfraStudentPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "名字", example = "芋头")
  17 + private String name;
  18 +
  19 + @Schema(description = "出生日期")
  20 + private LocalDateTime birthday;
  21 +
  22 + @Schema(description = "性别", example = "1")
  23 + private Integer sex;
  24 +
  25 + @Schema(description = "是否有效", example = "true")
  26 + private Boolean enabled;
  27 +
  28 + @Schema(description = "创建时间")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + private LocalDateTime[] createTime;
  31 +
  32 +}
0 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +import java.time.LocalDateTime;
  8 +import cn.idev.excel.annotation.*;
  9 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  10 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  11 +
  12 +@Schema(description = "管理后台 - 学生 Response VO")
  13 +@Data
  14 +@ExcelIgnoreUnannotated
  15 +public class InfraStudentRespVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + @ExcelProperty("编号")
  19 + private Long id;
  20 +
  21 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  22 + @ExcelProperty("名字")
  23 + private String name;
  24 +
  25 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  26 + @ExcelProperty("简介")
  27 + private String description;
  28 +
  29 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  30 + @ExcelProperty("出生日期")
  31 + private LocalDateTime birthday;
  32 +
  33 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  34 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  35 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  36 + private Integer sex;
  37 +
  38 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  39 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  40 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  41 + private Boolean enabled;
  42 +
  43 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  44 + @ExcelProperty("头像")
  45 + private String avatar;
  46 +
  47 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  48 + @ExcelProperty("附件")
  49 + private String video;
  50 +
  51 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  52 + @ExcelProperty("备注")
  53 + private String memo;
  54 +
  55 + @Schema(description = "创建时间")
  56 + @ExcelProperty("创建时间")
  57 + private LocalDateTime createTime;
  58 +
  59 +}
0 60 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import jakarta.validation.constraints.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  11 +@Data
  12 +public class InfraStudentSaveReqVO {
  13 +
  14 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  15 + private Long id;
  16 +
  17 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  18 + @NotEmpty(message = "名字不能为空")
  19 + private String name;
  20 +
  21 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  22 + @NotEmpty(message = "简介不能为空")
  23 + private String description;
  24 +
  25 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  26 + @NotNull(message = "出生日期不能为空")
  27 + private LocalDateTime birthday;
  28 +
  29 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  30 + @NotNull(message = "性别不能为空")
  31 + private Integer sex;
  32 +
  33 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  34 + @NotNull(message = "是否有效不能为空")
  35 + private Boolean enabled;
  36 +
  37 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  38 + @NotEmpty(message = "头像不能为空")
  39 + private String avatar;
  40 +
  41 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  42 + @NotEmpty(message = "附件不能为空")
  43 + private String video;
  44 +
  45 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  46 + @NotEmpty(message = "备注不能为空")
  47 + private String memo;
  48 +
  49 +}
0 50 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import jakarta.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  9 +
  10 +/**
  11 + * 学生 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface InfraStudentService {
  16 +
  17 + /**
  18 + * 创建学生
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 导入学生
  27 + *
  28 + * @param importList 导入信息
  29 + * @return 导入结果
  30 + */
  31 + InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList);
  32 +
  33 + /**
  34 + * 更新学生
  35 + *
  36 + * @param updateReqVO 更新信息
  37 + */
  38 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
  39 +
  40 + /**
  41 + * 删除学生
  42 + *
  43 + * @param id 编号
  44 + */
  45 + void deleteStudent(Long id);
  46 +
  47 + /**
  48 + * 批量删除学生
  49 + *
  50 + * @param ids 编号
  51 + */
  52 + void deleteStudentListByIds(List<Long> ids);
  53 +
  54 + /**
  55 + * 获得学生
  56 + *
  57 + * @param id 编号
  58 + * @return 学生
  59 + */
  60 + InfraStudentDO getStudent(Long id);
  61 +
  62 + /**
  63 + * 获得学生分页
  64 + *
  65 + * @param pageReqVO 分页查询
  66 + * @return 学生分页
  67 + */
  68 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  69 +
  70 +}
0 71 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import org.springframework.stereotype.Service;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.transaction.annotation.Transactional;
  8 +
  9 +import java.util.*;
  10 +import java.util.concurrent.atomic.AtomicInteger;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  15 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  16 +
  17 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class InfraStudentServiceImpl implements InfraStudentService {
  32 +
  33 + @Resource
  34 + private InfraStudentMapper studentMapper;
  35 +
  36 + @Override
  37 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  38 + // 插入
  39 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  40 + studentMapper.insert(student);
  41 +
  42 + // 返回
  43 + return student.getId();
  44 + }
  45 +
  46 + @Override
  47 + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入
  48 + public InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList) {
  49 + if (CollUtil.isEmpty(importList)) {
  50 + return InfraStudentImportRespVO.builder()
  51 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  52 + }
  53 + // 遍历,逐个创建
  54 + InfraStudentImportRespVO respVO = InfraStudentImportRespVO.builder()
  55 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  56 + AtomicInteger index = new AtomicInteger(1);
  57 + importList.forEach(importItem -> {
  58 + int currentIndex = index.getAndIncrement();
  59 + try {
  60 + createStudent(BeanUtils.toBean(importItem, InfraStudentSaveReqVO.class));
  61 + respVO.setSuccessCount(respVO.getSuccessCount() + 1);
  62 + } catch (Exception ex) {
  63 + respVO.getFailureRows().put(currentIndex, ex.getMessage());
  64 + }
  65 + });
  66 + respVO.setFailureCount(respVO.getFailureRows().size());
  67 + return respVO;
  68 + }
  69 +
  70 + @Override
  71 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  72 + // 校验存在
  73 + validateStudentExists(updateReqVO.getId());
  74 + // 更新
  75 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  76 + studentMapper.updateById(updateObj);
  77 + }
  78 +
  79 + @Override
  80 + public void deleteStudent(Long id) {
  81 + // 校验存在
  82 + validateStudentExists(id);
  83 + // 删除
  84 + studentMapper.deleteById(id);
  85 + }
  86 +
  87 + @Override
  88 + public void deleteStudentListByIds(List<Long> ids) {
  89 + // 删除
  90 + studentMapper.deleteByIds(ids);
  91 + }
  92 +
  93 +
  94 + private void validateStudentExists(Long id) {
  95 + if (studentMapper.selectById(id) == null) {
  96 + throw exception(STUDENT_NOT_EXISTS);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public InfraStudentDO getStudent(Long id) {
  102 + return studentMapper.selectById(id);
  103 + }
  104 +
  105 + @Override
  106 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  107 + return studentMapper.selectPage(pageReqVO);
  108 + }
  109 +
  110 +}
0 111 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +
  6 +import jakarta.annotation.Resource;
  7 +
  8 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  9 +
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  12 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +
  15 +import jakarta.annotation.Resource;
  16 +import org.springframework.context.annotation.Import;
  17 +import java.util.*;
  18 +import java.time.LocalDateTime;
  19 +
  20 +import static cn.hutool.core.util.RandomUtil.*;
  21 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  22 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  27 +import static org.junit.jupiter.api.Assertions.*;
  28 +import static org.mockito.Mockito.*;
  29 +
  30 +/**
  31 + * {@link InfraStudentServiceImpl} 的单元测试类
  32 + *
  33 + * @author 芋道源码
  34 + */
  35 +@Import(InfraStudentServiceImpl.class)
  36 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  37 +
  38 + @Resource
  39 + private InfraStudentServiceImpl studentService;
  40 +
  41 + @Resource
  42 + private InfraStudentMapper studentMapper;
  43 +
  44 + @Test
  45 + public void testCreateStudent_success() {
  46 + // 准备参数
  47 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  48 +
  49 + // 调用
  50 + Long studentId = studentService.createStudent(createReqVO);
  51 + // 断言
  52 + assertNotNull(studentId);
  53 + // 校验记录的属性是否正确
  54 + InfraStudentDO student = studentMapper.selectById(studentId);
  55 + assertPojoEquals(createReqVO, student, "id");
  56 + }
  57 +
  58 + @Test
  59 + public void testUpdateStudent_success() {
  60 + // mock 数据
  61 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  62 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  63 + // 准备参数
  64 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  65 + o.setId(dbStudent.getId()); // 设置更新的 ID
  66 + });
  67 +
  68 + // 调用
  69 + studentService.updateStudent(updateReqVO);
  70 + // 校验是否更新正确
  71 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  72 + assertPojoEquals(updateReqVO, student);
  73 + }
  74 +
  75 + @Test
  76 + public void testUpdateStudent_notExists() {
  77 + // 准备参数
  78 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  79 +
  80 + // 调用, 并断言异常
  81 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  82 + }
  83 +
  84 + @Test
  85 + public void testDeleteStudent_success() {
  86 + // mock 数据
  87 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  88 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  89 + // 准备参数
  90 + Long id = dbStudent.getId();
  91 +
  92 + // 调用
  93 + studentService.deleteStudent(id);
  94 + // 校验数据不存在了
  95 + assertNull(studentMapper.selectById(id));
  96 + }
  97 +
  98 + @Test
  99 + public void testDeleteStudent_notExists() {
  100 + // 准备参数
  101 + Long id = randomLongId();
  102 +
  103 + // 调用, 并断言异常
  104 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  105 + }
  106 +
  107 + @Test
  108 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  109 + public void testGetStudentPage() {
  110 + // mock 数据
  111 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  112 + o.setName(null);
  113 + o.setBirthday(null);
  114 + o.setSex(null);
  115 + o.setEnabled(null);
  116 + o.setCreateTime(null);
  117 + });
  118 + studentMapper.insert(dbStudent);
  119 + // 测试 name 不匹配
  120 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  121 + // 测试 birthday 不匹配
  122 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  123 + // 测试 sex 不匹配
  124 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  125 + // 测试 enabled 不匹配
  126 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  127 + // 测试 createTime 不匹配
  128 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  129 + // 准备参数
  130 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  131 + reqVO.setName(null);
  132 + reqVO.setBirthday(null);
  133 + reqVO.setSex(null);
  134 + reqVO.setEnabled(null);
  135 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  136 +
  137 + // 调用
  138 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  139 + // 断言
  140 + assertEquals(1, pageResult.getTotal());
  141 + assertEquals(1, pageResult.getList().size());
  142 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  143 + }
  144 +
  145 +}
0 146 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +SELECT @parentId := LAST_INSERT_ID();
  13 +
  14 +-- 按钮 SQL
  15 +INSERT INTO system_menu(
  16 + name, permission, type, sort, parent_id,
  17 + path, icon, component, status
  18 +)
  19 +VALUES (
  20 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  21 + '', '', '', 0
  22 +);
  23 +INSERT INTO system_menu(
  24 + name, permission, type, sort, parent_id,
  25 + path, icon, component, status
  26 +)
  27 +VALUES (
  28 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  29 + '', '', '', 0
  30 +);
  31 +INSERT INTO system_menu(
  32 + name, permission, type, sort, parent_id,
  33 + path, icon, component, status
  34 +)
  35 +VALUES (
  36 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  37 + '', '', '', 0
  38 +);
  39 +INSERT INTO system_menu(
  40 + name, permission, type, sort, parent_id,
  41 + path, icon, component, status
  42 +)
  43 +VALUES (
  44 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  45 + '', '', '', 0
  46 +);
  47 +INSERT INTO system_menu(
  48 + name, permission, type, sort, parent_id,
  49 + path, icon, component, status
  50 +)
  51 +VALUES (
  52 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  53 + '', '', '', 0
  54 +);
  55 +INSERT INTO system_menu(
  56 + name, permission, type, sort, parent_id,
  57 + path, icon, component, status
  58 +)
  59 +VALUES (
  60 + '学生导入', 'infra:student:import', 3, 6, @parentId,
  61 + '', '', '', 0
  62 +);
0 63 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/ts/data 0 → 100644
  1 +import type { VbenFormSchema } from '#/adapter/form';
  2 +import type { VxeTableGridOptions } from '#/adapter/vxe-table';
  3 +import type { InfraStudentApi } from '#/api/infra/demo';
  4 +
  5 +import { DICT_TYPE } from '@vben/constants';
  6 +import { getDictOptions } from '@vben/hooks';
  7 +
  8 +import { getRangePickerDefaultProps } from '#/utils';
  9 +
  10 +/** 新增/修改的表单 */
  11 +export function useFormSchema(): VbenFormSchema[] {
  12 + return [
  13 + {
  14 + fieldName: 'id',
  15 + component: 'Input',
  16 + dependencies: {
  17 + triggerFields: [''],
  18 + show: () => false,
  19 + },
  20 + },
  21 + {
  22 + fieldName: 'name',
  23 + label: '名字',
  24 + rules: 'required',
  25 + component: 'Input',
  26 + componentProps: {
  27 + placeholder: '请输入名字',
  28 + },
  29 + },
  30 + {
  31 + fieldName: 'description',
  32 + label: '简介',
  33 + rules: 'required',
  34 + component: 'Textarea',
  35 + componentProps: {
  36 + placeholder: '请输入简介',
  37 + },
  38 + },
  39 + {
  40 + fieldName: 'birthday',
  41 + label: '出生日期',
  42 + rules: 'required',
  43 + component: 'DatePicker',
  44 + componentProps: {
  45 + showTime: true,
  46 + format: 'YYYY-MM-DD HH:mm:ss',
  47 + valueFormat: 'x',
  48 + },
  49 + },
  50 + {
  51 + fieldName: 'sex',
  52 + label: '性别',
  53 + rules: 'required',
  54 + component: 'Select',
  55 + componentProps: {
  56 + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'),
  57 + placeholder: '请选择性别',
  58 + },
  59 + },
  60 + {
  61 + fieldName: 'enabled',
  62 + label: '是否有效',
  63 + rules: 'required',
  64 + component: 'RadioGroup',
  65 + componentProps: {
  66 + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
  67 + buttonStyle: 'solid',
  68 + optionType: 'button',
  69 + },
  70 + },
  71 + {
  72 + fieldName: 'avatar',
  73 + label: '头像',
  74 + rules: 'required',
  75 + component: 'ImageUpload',
  76 + },
  77 + {
  78 + fieldName: 'video',
  79 + label: '附件',
  80 + rules: 'required',
  81 + component: 'FileUpload',
  82 + },
  83 + {
  84 + fieldName: 'memo',
  85 + label: '备注',
  86 + rules: 'required',
  87 + component: 'RichTextarea',
  88 + },
  89 + ];
  90 +}
  91 +
  92 +/** 导入的表单 */
  93 +export function useImportFormSchema(): VbenFormSchema[] {
  94 + return [
  95 + {
  96 + fieldName: 'file',
  97 + label: '学生数据',
  98 + component: 'Upload',
  99 + rules: 'required',
  100 + help: '仅允许导入 xls、xlsx 格式文件',
  101 + },
  102 + ];
  103 +}
  104 +
  105 +/** 列表的搜索表单 */
  106 +export function useGridFormSchema(): VbenFormSchema[] {
  107 + return [
  108 + {
  109 + fieldName: 'name',
  110 + label: '名字',
  111 + component: 'Input',
  112 + componentProps: {
  113 + allowClear: true,
  114 + placeholder: '请输入名字',
  115 + },
  116 + },
  117 + {
  118 + fieldName: 'birthday',
  119 + label: '出生日期',
  120 + component: 'RangePicker',
  121 + componentProps: {
  122 + ...getRangePickerDefaultProps(),
  123 + allowClear: true,
  124 + },
  125 + },
  126 + {
  127 + fieldName: 'sex',
  128 + label: '性别',
  129 + component: 'Select',
  130 + componentProps: {
  131 + allowClear: true,
  132 + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'),
  133 + placeholder: '请选择性别',
  134 + },
  135 + },
  136 + {
  137 + fieldName: 'enabled',
  138 + label: '是否有效',
  139 + component: 'Select',
  140 + componentProps: {
  141 + allowClear: true,
  142 + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
  143 + placeholder: '请选择是否有效',
  144 + },
  145 + },
  146 + {
  147 + fieldName: 'createTime',
  148 + label: '创建时间',
  149 + component: 'RangePicker',
  150 + componentProps: {
  151 + ...getRangePickerDefaultProps(),
  152 + allowClear: true,
  153 + },
  154 + },
  155 + ];
  156 +}
  157 +
  158 +/** 列表的字段 */
  159 +export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>['columns'] {
  160 + return [
  161 + { type: 'checkbox', width: 40 },
  162 + {
  163 + field: 'id',
  164 + title: '编号',
  165 + minWidth: 120,
  166 + cellRender: {
  167 + name: 'CellDict',
  168 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  169 + },
  170 + },
  171 + {
  172 + field: 'name',
  173 + title: '名字',
  174 + minWidth: 120,
  175 + cellRender: {
  176 + name: 'CellDict',
  177 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  178 + },
  179 + },
  180 + {
  181 + field: 'description',
  182 + title: '简介',
  183 + minWidth: 120,
  184 + cellRender: {
  185 + name: 'CellDict',
  186 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  187 + },
  188 + },
  189 + {
  190 + field: 'birthday',
  191 + title: '出生日期',
  192 + minWidth: 120,
  193 + formatter: 'formatDateTime',
  194 + },
  195 + {
  196 + field: 'sex',
  197 + title: '性别',
  198 + minWidth: 120,
  199 + cellRender: {
  200 + name: 'CellDict',
  201 + props: { type: DICT_TYPE.SYSTEM_USER_SEX },
  202 + },
  203 + },
  204 + {
  205 + field: 'enabled',
  206 + title: '是否有效',
  207 + minWidth: 120,
  208 + cellRender: {
  209 + name: 'CellDict',
  210 + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
  211 + },
  212 + },
  213 + {
  214 + field: 'avatar',
  215 + title: '头像',
  216 + minWidth: 120,
  217 + cellRender: {
  218 + name: 'CellDict',
  219 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  220 + },
  221 + },
  222 + {
  223 + field: 'video',
  224 + title: '附件',
  225 + minWidth: 120,
  226 + cellRender: {
  227 + name: 'CellDict',
  228 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  229 + },
  230 + },
  231 + {
  232 + field: 'memo',
  233 + title: '备注',
  234 + minWidth: 120,
  235 + cellRender: {
  236 + name: 'CellDict',
  237 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  238 + },
  239 + },
  240 + {
  241 + field: 'createTime',
  242 + title: '创建时间',
  243 + minWidth: 120,
  244 + formatter: 'formatDateTime',
  245 + },
  246 + {
  247 + title: '操作',
  248 + width: 200,
  249 + fixed: 'right',
  250 + slots: { default: 'actions' },
  251 + },
  252 + ];
  253 +}
  254 +
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/ts/index 0 → 100644
  1 +import type { PageParam, PageResult } from '@vben/request';
  2 +import type { Dayjs } from 'dayjs';
  3 +
  4 +import { requestClient } from '#/api/request';
  5 +
  6 +export namespace InfraStudentApi {
  7 + /** 学生信息 */
  8 + export interface Student {
  9 + id: number; // 编号
  10 + name?: string; // 名字
  11 + description?: string; // 简介
  12 + birthday?: string | Dayjs; // 出生日期
  13 + sex?: number; // 性别
  14 + enabled?: boolean; // 是否有效
  15 + avatar?: string; // 头像
  16 + video?: string; // 附件
  17 + memo?: string; // 备注
  18 + }
  19 +}
  20 +
  21 +/** 查询学生分页 */
  22 +export function getStudentPage(params: PageParam) {
  23 + return requestClient.get<PageResult<InfraStudentApi.Student>>(
  24 + '/infra/student/page',
  25 + { params },
  26 + );
  27 +}
  28 +
  29 +/** 查询学生详情 */
  30 +export function getStudent(id: number) {
  31 + return requestClient.get<InfraStudentApi.Student>(
  32 + `/infra/student/get?id=${id}`,
  33 + );
  34 +}
  35 +
  36 +/** 新增学生 */
  37 +export function createStudent(data: InfraStudentApi.Student) {
  38 + return requestClient.post('/infra/student/create', data);
  39 +}
  40 +
  41 +/** 修改学生 */
  42 +export function updateStudent(data: InfraStudentApi.Student) {
  43 + return requestClient.put('/infra/student/update', data);
  44 +}
  45 +
  46 +/** 删除学生 */
  47 +export function deleteStudent(id: number) {
  48 + return requestClient.delete(`/infra/student/delete?id=${id}`);
  49 +}
  50 +
  51 +/** 批量删除学生 */
  52 +export function deleteStudentList(ids: number[]) {
  53 + return requestClient.delete(
  54 + `/infra/student/delete-list?ids=${ids.join(',')}`,
  55 + );
  56 +}
  57 +
  58 +/** 导出学生 */
  59 +export function exportStudent(params: any) {
  60 + return requestClient.download('/infra/student/export-excel', { params });
  61 +}
  62 +
  63 +/** 下载学生导入模板 */
  64 +export function importStudentTemplate() {
  65 + return requestClient.download('/infra/student/get-import-template');
  66 +}
  67 +
  68 +/** 导入学生 */
  69 +export function importStudent(file: File) {
  70 + return requestClient.upload('/infra/student/import', { file });
  71 +}
0 72 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/vue/form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { InfraStudentApi } from '#/api/infra/demo';
  3 +
  4 +import { computed, ref } from 'vue';
  5 +
  6 +import { useVbenModal } from '@vben/common-ui';
  7 +
  8 +import { message } from 'ant-design-vue';
  9 +
  10 +import { useVbenForm } from '#/adapter/form';
  11 +import { createStudent, getStudent, updateStudent } from '#/api/infra/demo';
  12 +import { $t } from '#/locales';
  13 +
  14 +import { useFormSchema } from '../data';
  15 +
  16 +const emit = defineEmits(['success']);
  17 +const formData = ref<InfraStudentApi.Student>();
  18 +const getTitle = computed(() => {
  19 + return formData.value?.id
  20 + ? $t('ui.actionTitle.edit', ['学生'])
  21 + : $t('ui.actionTitle.create', ['学生']);
  22 +});
  23 +
  24 +const [Form, formApi] = useVbenForm({
  25 + commonConfig: {
  26 + componentProps: {
  27 + class: 'w-full',
  28 + },
  29 + formItemClass: 'col-span-2',
  30 + labelWidth: 80,
  31 + },
  32 + layout: 'horizontal',
  33 + schema: useFormSchema(),
  34 + showDefaultActions: false,
  35 +});
  36 +
  37 +const [Modal, modalApi] = useVbenModal({
  38 + async onConfirm() {
  39 + const { valid } = await formApi.validate();
  40 + if (!valid) {
  41 + return;
  42 + }
  43 + modalApi.lock();
  44 + // 提交表单
  45 + const data = (await formApi.getValues()) as InfraStudentApi.Student;
  46 + try {
  47 + await (formData.value?.id ? updateStudent(data) : createStudent(data));
  48 + // 关闭并提示
  49 + await modalApi.close();
  50 + emit('success');
  51 + message.success($t('ui.actionMessage.operationSuccess'));
  52 + } finally {
  53 + modalApi.unlock();
  54 + }
  55 + },
  56 + async onOpenChange(isOpen: boolean) {
  57 + if (!isOpen) {
  58 + formData.value = undefined;
  59 + return;
  60 + }
  61 + // 加载数据
  62 + const data = modalApi.getData<InfraStudentApi.Student>();
  63 + if (!data || !data.id) {
  64 + return;
  65 + }
  66 + modalApi.lock();
  67 + try {
  68 + formData.value = await getStudent(data.id);
  69 + // 设置到 values
  70 + await formApi.setValues(formData.value);
  71 + } finally {
  72 + modalApi.unlock();
  73 + }
  74 + },
  75 +});
  76 +</script>
  77 +
  78 +<template>
  79 + <Modal :title="getTitle">
  80 + <Form class="mx-4" />
  81 + </Modal>
  82 +</template>
0 83 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/vue/import-form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { FileType } from 'ant-design-vue/es/upload/interface';
  3 +
  4 +import { useVbenModal } from '@vben/common-ui';
  5 +import { downloadFileFromBlobPart } from '@vben/utils';
  6 +
  7 +import { Button, message, Upload } from 'ant-design-vue';
  8 +
  9 +import { useVbenForm } from '#/adapter/form';
  10 +import { importStudent, importStudentTemplate } from '#/api/infra/demo';
  11 +import { $t } from '#/locales';
  12 +
  13 +import { useImportFormSchema } from '../data';
  14 +
  15 +const emit = defineEmits(['success']);
  16 +
  17 +const [Form, formApi] = useVbenForm({
  18 + commonConfig: {
  19 + formItemClass: 'col-span-2',
  20 + labelWidth: 120,
  21 + },
  22 + layout: 'horizontal',
  23 + schema: useImportFormSchema(),
  24 + showDefaultActions: false,
  25 +});
  26 +
  27 +const [Modal, modalApi] = useVbenModal({
  28 + async onConfirm() {
  29 + const { valid } = await formApi.validate();
  30 + if (!valid) {
  31 + return;
  32 + }
  33 + modalApi.lock();
  34 + // 提交表单
  35 + const data = await formApi.getValues();
  36 + try {
  37 + await importStudent(data.file);
  38 + // 关闭并提示
  39 + await modalApi.close();
  40 + emit('success');
  41 + message.success($t('ui.actionMessage.operationSuccess'));
  42 + } finally {
  43 + modalApi.unlock();
  44 + }
  45 + },
  46 +});
  47 +
  48 +/** 上传前 */
  49 +function beforeUpload(file: FileType) {
  50 + formApi.setFieldValue('file', file);
  51 + return false;
  52 +}
  53 +
  54 +/** 下载模板 */
  55 +async function handleDownload() {
  56 + const data = await importStudentTemplate();
  57 + downloadFileFromBlobPart({ fileName: '学生导入模板.xls', source: data });
  58 +}
  59 +</script>
  60 +
  61 +<template>
  62 + <Modal title="导入学生" class="w-1/3">
  63 + <Form class="mx-4">
  64 + <template #file>
  65 + <div class="w-full">
  66 + <Upload
  67 + :max-count="1"
  68 + accept=".xls,.xlsx"
  69 + :before-upload="beforeUpload"
  70 + >
  71 + <Button type="primary"> 选择 Excel 文件 </Button>
  72 + </Upload>
  73 + </div>
  74 + </template>
  75 + </Form>
  76 + <template #prepend-footer>
  77 + <div class="flex flex-auto items-center">
  78 + <Button @click="handleDownload"> 下载导入模板 </Button>
  79 + </div>
  80 + </template>
  81 + </Modal>
  82 +</template>
0 83 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/vue/index 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { VxeTableGridOptions } from '#/adapter/vxe-table';
  3 +import type { InfraStudentApi } from '#/api/infra/demo';
  4 +
  5 +import { ref } from 'vue';
  6 +
  7 +import { confirm, Page, useVbenModal } from '@vben/common-ui';
  8 +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils';
  9 +
  10 +import { message } from 'ant-design-vue';
  11 +
  12 +import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
  13 +import {
  14 + deleteStudent,
  15 + deleteStudentList,
  16 + exportStudent,
  17 + getStudentPage,
  18 +} from '#/api/infra/demo';
  19 +import StudentImport from './modules/import-form.vue';
  20 +import { $t } from '#/locales';
  21 +
  22 +import { useGridColumns, useGridFormSchema } from './data';
  23 +import Form from './modules/form.vue';
  24 +
  25 +const [FormModal, formModalApi] = useVbenModal({
  26 + connectedComponent: Form,
  27 + destroyOnClose: true,
  28 +});
  29 +const [ImportFormModal, importFormModalApi] = useVbenModal({
  30 + connectedComponent: StudentImport,
  31 + destroyOnClose: true,
  32 +});
  33 +
  34 +/** 导入学生 */
  35 +function handleImport() {
  36 + importFormModalApi.open();
  37 +}
  38 +
  39 +/** 刷新表格 */
  40 +function handleRefresh() {
  41 + gridApi.query();
  42 +}
  43 +
  44 +/** 创建学生 */
  45 +function handleCreate() {
  46 + formModalApi.setData(null).open();
  47 +}
  48 +
  49 +/** 编辑学生 */
  50 +function handleEdit(row: InfraStudentApi.Student) {
  51 + formModalApi.setData(row).open();
  52 +}
  53 +
  54 +/** 删除学生 */
  55 +async function handleDelete(row: InfraStudentApi.Student) {
  56 + const hideLoading = message.loading({
  57 + content: $t('ui.actionMessage.deleting', [row.id]),
  58 + duration: 0,
  59 + });
  60 + try {
  61 + await deleteStudent(row.id!);
  62 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  63 + handleRefresh();
  64 + } finally {
  65 + hideLoading();
  66 + }
  67 +}
  68 +
  69 +/** 批量删除学生 */
  70 +async function handleDeleteBatch() {
  71 + await confirm($t('ui.actionMessage.deleteBatchConfirm'));
  72 + const hideLoading = message.loading({
  73 + content: $t('ui.actionMessage.deletingBatch'),
  74 + duration: 0,
  75 + });
  76 + try {
  77 + await deleteStudentList(checkedIds.value);
  78 + checkedIds.value = [];
  79 + message.success($t('ui.actionMessage.deleteSuccess'));
  80 + handleRefresh();
  81 + } finally {
  82 + hideLoading();
  83 + }
  84 +}
  85 +
  86 +const checkedIds = ref<number[]>([]);
  87 +function handleRowCheckboxChange({
  88 + records,
  89 +}: {
  90 + records: InfraStudentApi.Student[];
  91 +}) {
  92 + checkedIds.value = records.map((item) => item.id!);
  93 +}
  94 +
  95 +/** 导出表格 */
  96 +async function handleExport() {
  97 + const data = await exportStudent(await gridApi.formApi.getValues());
  98 + downloadFileFromBlobPart({ fileName: '学生.xls', source: data });
  99 +}
  100 +
  101 +
  102 +const [Grid, gridApi] = useVbenVxeGrid({
  103 + formOptions: {
  104 + schema: useGridFormSchema(),
  105 + },
  106 + gridOptions: {
  107 + columns: useGridColumns(),
  108 + height: 'auto',
  109 + keepSource: true,
  110 + proxyConfig: {
  111 + ajax: {
  112 + query: async ({ page }, formValues) => {
  113 + return await getStudentPage({
  114 + pageNo: page.currentPage,
  115 + pageSize: page.pageSize,
  116 + ...formValues,
  117 + });
  118 + },
  119 + },
  120 + },
  121 + rowConfig: {
  122 + keyField: 'id',
  123 + isHover: true,
  124 + },
  125 + toolbarConfig: {
  126 + refresh: true,
  127 + search: true,
  128 + },
  129 + } as VxeTableGridOptions<InfraStudentApi.Student>,
  130 + gridEvents: {
  131 + checkboxAll: handleRowCheckboxChange,
  132 + checkboxChange: handleRowCheckboxChange,
  133 + },
  134 +});
  135 +</script>
  136 +
  137 +<template>
  138 + <Page auto-content-height>
  139 + <FormModal @success="handleRefresh" />
  140 + <ImportFormModal @success="handleRefresh" />
  141 + <Grid table-title="学生列表">
  142 + <template #toolbar-tools>
  143 + <TableAction
  144 + :actions="[
  145 + {
  146 + label: $t('ui.actionTitle.create', ['学生']),
  147 + type: 'primary',
  148 + icon: ACTION_ICON.ADD,
  149 + auth: ['infra:student:create'],
  150 + onClick: handleCreate,
  151 + },
  152 + {
  153 + label: '导入',
  154 + type: 'primary',
  155 + auth: ['infra:student:import'],
  156 + onClick: handleImport,
  157 + },
  158 + {
  159 + label: $t('ui.actionTitle.export'),
  160 + type: 'primary',
  161 + icon: ACTION_ICON.DOWNLOAD,
  162 + auth: ['infra:student:export'],
  163 + onClick: handleExport,
  164 + },
  165 + {
  166 + label: $t('ui.actionTitle.deleteBatch'),
  167 + type: 'primary',
  168 + danger: true,
  169 + icon: ACTION_ICON.DELETE,
  170 + auth: ['infra:student:delete'],
  171 + disabled: isEmpty(checkedIds),
  172 + onClick: handleDeleteBatch,
  173 + },
  174 + ]"
  175 + />
  176 + </template>
  177 + <template #actions="{ row }">
  178 + <TableAction
  179 + :actions="[
  180 + {
  181 + label: $t('common.edit'),
  182 + type: 'link',
  183 + icon: ACTION_ICON.EDIT,
  184 + auth: ['infra:student:update'],
  185 + onClick: handleEdit.bind(null, row),
  186 + },
  187 + {
  188 + label: $t('common.delete'),
  189 + type: 'link',
  190 + danger: true,
  191 + icon: ACTION_ICON.DELETE,
  192 + auth: ['infra:student:delete'],
  193 + popConfirm: {
  194 + title: $t('ui.actionMessage.deleteConfirm', [row.id]),
  195 + confirm: handleDelete.bind(null, row),
  196 + },
  197 + },
  198 + ]"
  199 + />
  200 + </template>
  201 + </Grid>
  202 + </Page>
  203 +</template>
0 204 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/xml/InfraStudentMapper 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentImportExcelVO",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportExcelVO.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentImportRespVO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportRespVO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentController",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentDO",
  21 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentMapper",
  24 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  25 +}, {
  26 + "contentPath" : "xml/InfraStudentMapper",
  27 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentServiceImpl",
  30 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  31 +}, {
  32 + "contentPath" : "java/InfraStudentService",
  33 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImplTest",
  36 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  37 +}, {
  38 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  39 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  40 +}, {
  41 + "contentPath" : "sql/sql",
  42 + "filePath" : "sql/sql.sql"
  43 +}, {
  44 + "contentPath" : "sql/h2",
  45 + "filePath" : "sql/h2.sql"
  46 +}, {
  47 + "contentPath" : "vue/index",
  48 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  49 +}, {
  50 + "contentPath" : "vue/form",
  51 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  52 +}, {
  53 + "contentPath" : "vue/import-form",
  54 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/import-form.vue"
  55 +}, {
  56 + "contentPath" : "ts/index",
  57 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  58 +} ]
0 59 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/ErrorCodeConstants_手动操作 0 → 100644
  1 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  2 +// ========== 学生 TODO 补充编号 ==========
  3 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
0 4 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import org.springframework.web.multipart.MultipartFile;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.security.access.prepost.PreAuthorize;
  8 +import io.swagger.v3.oas.annotations.tags.Tag;
  9 +import io.swagger.v3.oas.annotations.Parameter;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +
  12 +import jakarta.validation.constraints.*;
  13 +import jakarta.validation.*;
  14 +import jakarta.servlet.http.*;
  15 +import java.util.*;
  16 +import java.io.IOException;
  17 +
  18 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  19 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  20 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  21 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  25 +
  26 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  27 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
  28 +
  29 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  30 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  31 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  32 +
  33 +@Tag(name = "管理后台 - 学生")
  34 +@RestController
  35 +@RequestMapping("/infra/student")
  36 +@Validated
  37 +public class InfraStudentController {
  38 +
  39 + @Resource
  40 + private InfraStudentService studentService;
  41 +
  42 + @PostMapping("/create")
  43 + @Operation(summary = "创建学生")
  44 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  45 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  46 + return success(studentService.createStudent(createReqVO));
  47 + }
  48 +
  49 + @PutMapping("/update")
  50 + @Operation(summary = "更新学生")
  51 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  52 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  53 + studentService.updateStudent(updateReqVO);
  54 + return success(true);
  55 + }
  56 +
  57 + @DeleteMapping("/delete")
  58 + @Operation(summary = "删除学生")
  59 + @Parameter(name = "id", description = "编号", required = true)
  60 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  61 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  62 + studentService.deleteStudent(id);
  63 + return success(true);
  64 + }
  65 +
  66 + @DeleteMapping("/delete-list")
  67 + @Parameter(name = "ids", description = "编号", required = true)
  68 + @Operation(summary = "批量删除学生")
  69 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  70 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  71 + studentService.deleteStudentListByIds(ids);
  72 + return success(true);
  73 + }
  74 +
  75 + @GetMapping("/get")
  76 + @Operation(summary = "获得学生")
  77 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  78 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  79 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  80 + InfraStudentDO student = studentService.getStudent(id);
  81 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  82 + }
  83 +
  84 + @GetMapping("/page")
  85 + @Operation(summary = "获得学生分页")
  86 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  87 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  88 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  89 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  90 + }
  91 +
  92 + @GetMapping("/export-excel")
  93 + @Operation(summary = "导出学生 Excel")
  94 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  95 + @ApiAccessLog(operateType = EXPORT)
  96 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  97 + HttpServletResponse response) throws IOException {
  98 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  99 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  100 + // 导出 Excel
  101 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  102 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  103 + }
  104 +
  105 + @GetMapping("/get-import-template")
  106 + @Operation(summary = "获得导入学生模板")
  107 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  108 + public void importTemplate(HttpServletResponse response) throws IOException {
  109 + ExcelUtils.write(response, "学生导入模板.xls", "数据",
  110 + InfraStudentImportExcelVO.class, Collections.emptyList());
  111 + }
  112 +
  113 + @PostMapping("/import")
  114 + @Operation(summary = "导入学生")
  115 + @Parameter(name = "file", description = "Excel 文件", required = true)
  116 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  117 + public CommonResult<InfraStudentImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
  118 + List<InfraStudentImportExcelVO> list = ExcelUtils.read(file, InfraStudentImportExcelVO.class);
  119 + return success(studentService.importStudentList(list));
  120 + }
  121 +
  122 +}
0 123 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +
  68 +}
0 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentImportExcelVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelProperty;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Builder;
  6 +import lombok.Data;
  7 +import lombok.NoArgsConstructor;
  8 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  9 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  10 +
  11 +/**
  12 + * 学生 Excel 导入 VO
  13 + */
  14 +@Data
  15 +@Builder
  16 +@AllArgsConstructor
  17 +@NoArgsConstructor
  18 +public class InfraStudentImportExcelVO {
  19 +
  20 + @ExcelProperty("名字")
  21 + private String name;
  22 +
  23 + @ExcelProperty("简介")
  24 + private String description;
  25 +
  26 + @ExcelProperty("出生日期")
  27 + private LocalDateTime birthday;
  28 +
  29 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  30 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  31 + private Integer sex;
  32 +
  33 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  34 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  35 + private Boolean enabled;
  36 +
  37 + @ExcelProperty("头像")
  38 + private String avatar;
  39 +
  40 + @ExcelProperty("附件")
  41 + private String video;
  42 +
  43 + @ExcelProperty("备注")
  44 + private String memo;
  45 +
  46 +}
0 47 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentImportRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Map;
  8 +
  9 +@Schema(description = "管理后台 - 学生导入 Response VO")
  10 +@Data
  11 +@Builder
  12 +public class InfraStudentImportRespVO {
  13 +
  14 + @Schema(description = "创建成功的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  15 + private Integer successCount;
  16 +
  17 + @Schema(description = "导入失败的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Integer failureCount;
  19 +
  20 + @Schema(description = "导入失败的数据集合,key 为行号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
  21 + private Map<Integer, String> failureRows;
  22 +
  23 +}
0 24 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +public class InfraStudentPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "名字", example = "芋头")
  17 + private String name;
  18 +
  19 + @Schema(description = "出生日期")
  20 + private LocalDateTime birthday;
  21 +
  22 + @Schema(description = "性别", example = "1")
  23 + private Integer sex;
  24 +
  25 + @Schema(description = "是否有效", example = "true")
  26 + private Boolean enabled;
  27 +
  28 + @Schema(description = "创建时间")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + private LocalDateTime[] createTime;
  31 +
  32 +}
0 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +import java.time.LocalDateTime;
  8 +import cn.idev.excel.annotation.*;
  9 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  10 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  11 +
  12 +@Schema(description = "管理后台 - 学生 Response VO")
  13 +@Data
  14 +@ExcelIgnoreUnannotated
  15 +public class InfraStudentRespVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + @ExcelProperty("编号")
  19 + private Long id;
  20 +
  21 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  22 + @ExcelProperty("名字")
  23 + private String name;
  24 +
  25 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  26 + @ExcelProperty("简介")
  27 + private String description;
  28 +
  29 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  30 + @ExcelProperty("出生日期")
  31 + private LocalDateTime birthday;
  32 +
  33 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  34 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  35 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  36 + private Integer sex;
  37 +
  38 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  39 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  40 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  41 + private Boolean enabled;
  42 +
  43 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  44 + @ExcelProperty("头像")
  45 + private String avatar;
  46 +
  47 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  48 + @ExcelProperty("附件")
  49 + private String video;
  50 +
  51 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  52 + @ExcelProperty("备注")
  53 + private String memo;
  54 +
  55 + @Schema(description = "创建时间")
  56 + @ExcelProperty("创建时间")
  57 + private LocalDateTime createTime;
  58 +
  59 +}
0 60 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import jakarta.validation.constraints.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  11 +@Data
  12 +public class InfraStudentSaveReqVO {
  13 +
  14 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  15 + private Long id;
  16 +
  17 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  18 + @NotEmpty(message = "名字不能为空")
  19 + private String name;
  20 +
  21 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  22 + @NotEmpty(message = "简介不能为空")
  23 + private String description;
  24 +
  25 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  26 + @NotNull(message = "出生日期不能为空")
  27 + private LocalDateTime birthday;
  28 +
  29 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  30 + @NotNull(message = "性别不能为空")
  31 + private Integer sex;
  32 +
  33 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  34 + @NotNull(message = "是否有效不能为空")
  35 + private Boolean enabled;
  36 +
  37 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  38 + @NotEmpty(message = "头像不能为空")
  39 + private String avatar;
  40 +
  41 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  42 + @NotEmpty(message = "附件不能为空")
  43 + private String video;
  44 +
  45 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  46 + @NotEmpty(message = "备注不能为空")
  47 + private String memo;
  48 +
  49 +}
0 50 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import jakarta.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  9 +
  10 +/**
  11 + * 学生 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface InfraStudentService {
  16 +
  17 + /**
  18 + * 创建学生
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 导入学生
  27 + *
  28 + * @param importList 导入信息
  29 + * @return 导入结果
  30 + */
  31 + InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList);
  32 +
  33 + /**
  34 + * 更新学生
  35 + *
  36 + * @param updateReqVO 更新信息
  37 + */
  38 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
  39 +
  40 + /**
  41 + * 删除学生
  42 + *
  43 + * @param id 编号
  44 + */
  45 + void deleteStudent(Long id);
  46 +
  47 + /**
  48 + * 批量删除学生
  49 + *
  50 + * @param ids 编号
  51 + */
  52 + void deleteStudentListByIds(List<Long> ids);
  53 +
  54 + /**
  55 + * 获得学生
  56 + *
  57 + * @param id 编号
  58 + * @return 学生
  59 + */
  60 + InfraStudentDO getStudent(Long id);
  61 +
  62 + /**
  63 + * 获得学生分页
  64 + *
  65 + * @param pageReqVO 分页查询
  66 + * @return 学生分页
  67 + */
  68 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  69 +
  70 +}
0 71 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import org.springframework.stereotype.Service;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.transaction.annotation.Transactional;
  8 +
  9 +import java.util.*;
  10 +import java.util.concurrent.atomic.AtomicInteger;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  15 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  16 +
  17 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class InfraStudentServiceImpl implements InfraStudentService {
  32 +
  33 + @Resource
  34 + private InfraStudentMapper studentMapper;
  35 +
  36 + @Override
  37 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  38 + // 插入
  39 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  40 + studentMapper.insert(student);
  41 +
  42 + // 返回
  43 + return student.getId();
  44 + }
  45 +
  46 + @Override
  47 + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入
  48 + public InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList) {
  49 + if (CollUtil.isEmpty(importList)) {
  50 + return InfraStudentImportRespVO.builder()
  51 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  52 + }
  53 + // 遍历,逐个创建
  54 + InfraStudentImportRespVO respVO = InfraStudentImportRespVO.builder()
  55 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  56 + AtomicInteger index = new AtomicInteger(1);
  57 + importList.forEach(importItem -> {
  58 + int currentIndex = index.getAndIncrement();
  59 + try {
  60 + createStudent(BeanUtils.toBean(importItem, InfraStudentSaveReqVO.class));
  61 + respVO.setSuccessCount(respVO.getSuccessCount() + 1);
  62 + } catch (Exception ex) {
  63 + respVO.getFailureRows().put(currentIndex, ex.getMessage());
  64 + }
  65 + });
  66 + respVO.setFailureCount(respVO.getFailureRows().size());
  67 + return respVO;
  68 + }
  69 +
  70 + @Override
  71 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  72 + // 校验存在
  73 + validateStudentExists(updateReqVO.getId());
  74 + // 更新
  75 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  76 + studentMapper.updateById(updateObj);
  77 + }
  78 +
  79 + @Override
  80 + public void deleteStudent(Long id) {
  81 + // 校验存在
  82 + validateStudentExists(id);
  83 + // 删除
  84 + studentMapper.deleteById(id);
  85 + }
  86 +
  87 + @Override
  88 + public void deleteStudentListByIds(List<Long> ids) {
  89 + // 删除
  90 + studentMapper.deleteByIds(ids);
  91 + }
  92 +
  93 +
  94 + private void validateStudentExists(Long id) {
  95 + if (studentMapper.selectById(id) == null) {
  96 + throw exception(STUDENT_NOT_EXISTS);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public InfraStudentDO getStudent(Long id) {
  102 + return studentMapper.selectById(id);
  103 + }
  104 +
  105 + @Override
  106 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  107 + return studentMapper.selectPage(pageReqVO);
  108 + }
  109 +
  110 +}
0 111 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +
  6 +import jakarta.annotation.Resource;
  7 +
  8 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  9 +
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  12 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +
  15 +import jakarta.annotation.Resource;
  16 +import org.springframework.context.annotation.Import;
  17 +import java.util.*;
  18 +import java.time.LocalDateTime;
  19 +
  20 +import static cn.hutool.core.util.RandomUtil.*;
  21 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  22 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  27 +import static org.junit.jupiter.api.Assertions.*;
  28 +import static org.mockito.Mockito.*;
  29 +
  30 +/**
  31 + * {@link InfraStudentServiceImpl} 的单元测试类
  32 + *
  33 + * @author 芋道源码
  34 + */
  35 +@Import(InfraStudentServiceImpl.class)
  36 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  37 +
  38 + @Resource
  39 + private InfraStudentServiceImpl studentService;
  40 +
  41 + @Resource
  42 + private InfraStudentMapper studentMapper;
  43 +
  44 + @Test
  45 + public void testCreateStudent_success() {
  46 + // 准备参数
  47 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  48 +
  49 + // 调用
  50 + Long studentId = studentService.createStudent(createReqVO);
  51 + // 断言
  52 + assertNotNull(studentId);
  53 + // 校验记录的属性是否正确
  54 + InfraStudentDO student = studentMapper.selectById(studentId);
  55 + assertPojoEquals(createReqVO, student, "id");
  56 + }
  57 +
  58 + @Test
  59 + public void testUpdateStudent_success() {
  60 + // mock 数据
  61 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  62 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  63 + // 准备参数
  64 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  65 + o.setId(dbStudent.getId()); // 设置更新的 ID
  66 + });
  67 +
  68 + // 调用
  69 + studentService.updateStudent(updateReqVO);
  70 + // 校验是否更新正确
  71 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  72 + assertPojoEquals(updateReqVO, student);
  73 + }
  74 +
  75 + @Test
  76 + public void testUpdateStudent_notExists() {
  77 + // 准备参数
  78 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  79 +
  80 + // 调用, 并断言异常
  81 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  82 + }
  83 +
  84 + @Test
  85 + public void testDeleteStudent_success() {
  86 + // mock 数据
  87 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  88 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  89 + // 准备参数
  90 + Long id = dbStudent.getId();
  91 +
  92 + // 调用
  93 + studentService.deleteStudent(id);
  94 + // 校验数据不存在了
  95 + assertNull(studentMapper.selectById(id));
  96 + }
  97 +
  98 + @Test
  99 + public void testDeleteStudent_notExists() {
  100 + // 准备参数
  101 + Long id = randomLongId();
  102 +
  103 + // 调用, 并断言异常
  104 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  105 + }
  106 +
  107 + @Test
  108 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  109 + public void testGetStudentPage() {
  110 + // mock 数据
  111 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  112 + o.setName(null);
  113 + o.setBirthday(null);
  114 + o.setSex(null);
  115 + o.setEnabled(null);
  116 + o.setCreateTime(null);
  117 + });
  118 + studentMapper.insert(dbStudent);
  119 + // 测试 name 不匹配
  120 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  121 + // 测试 birthday 不匹配
  122 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  123 + // 测试 sex 不匹配
  124 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  125 + // 测试 enabled 不匹配
  126 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  127 + // 测试 createTime 不匹配
  128 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  129 + // 准备参数
  130 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  131 + reqVO.setName(null);
  132 + reqVO.setBirthday(null);
  133 + reqVO.setSex(null);
  134 + reqVO.setEnabled(null);
  135 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  136 +
  137 + // 调用
  138 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  139 + // 断言
  140 + assertEquals(1, pageResult.getTotal());
  141 + assertEquals(1, pageResult.getList().size());
  142 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  143 + }
  144 +
  145 +}
0 146 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +SELECT @parentId := LAST_INSERT_ID();
  13 +
  14 +-- 按钮 SQL
  15 +INSERT INTO system_menu(
  16 + name, permission, type, sort, parent_id,
  17 + path, icon, component, status
  18 +)
  19 +VALUES (
  20 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  21 + '', '', '', 0
  22 +);
  23 +INSERT INTO system_menu(
  24 + name, permission, type, sort, parent_id,
  25 + path, icon, component, status
  26 +)
  27 +VALUES (
  28 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  29 + '', '', '', 0
  30 +);
  31 +INSERT INTO system_menu(
  32 + name, permission, type, sort, parent_id,
  33 + path, icon, component, status
  34 +)
  35 +VALUES (
  36 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  37 + '', '', '', 0
  38 +);
  39 +INSERT INTO system_menu(
  40 + name, permission, type, sort, parent_id,
  41 + path, icon, component, status
  42 +)
  43 +VALUES (
  44 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  45 + '', '', '', 0
  46 +);
  47 +INSERT INTO system_menu(
  48 + name, permission, type, sort, parent_id,
  49 + path, icon, component, status
  50 +)
  51 +VALUES (
  52 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  53 + '', '', '', 0
  54 +);
  55 +INSERT INTO system_menu(
  56 + name, permission, type, sort, parent_id,
  57 + path, icon, component, status
  58 +)
  59 +VALUES (
  60 + '学生导入', 'infra:student:import', 3, 6, @parentId,
  61 + '', '', '', 0
  62 +);
0 63 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/ts/index 0 → 100644
  1 +import type { PageParam, PageResult } from '@vben/request';
  2 +import type { Dayjs } from 'dayjs';
  3 +
  4 +import { requestClient } from '#/api/request';
  5 +
  6 +export namespace StudentApi {
  7 + /** 学生信息 */
  8 + export interface Student {
  9 + id: number; // 编号
  10 + name?: string; // 名字
  11 + description?: string; // 简介
  12 + birthday?: string | Dayjs; // 出生日期
  13 + sex?: number; // 性别
  14 + enabled?: boolean; // 是否有效
  15 + avatar?: string; // 头像
  16 + video?: string; // 附件
  17 + memo?: string; // 备注
  18 + }
  19 +}
  20 +
  21 +/** 查询学生分页 */
  22 +export function getStudentPage(params: PageParam) {
  23 + return requestClient.get<PageResult<StudentApi.Student>>('/infra/student/page', { params });
  24 +}
  25 +
  26 +/** 查询学生详情 */
  27 +export function getStudent(id: number) {
  28 + return requestClient.get<StudentApi.Student>(`/infra/student/get?id=${id}`);
  29 +}
  30 +
  31 +/** 新增学生 */
  32 +export function createStudent(data: StudentApi.Student) {
  33 + return requestClient.post('/infra/student/create', data);
  34 +}
  35 +
  36 +/** 修改学生 */
  37 +export function updateStudent(data: StudentApi.Student) {
  38 + return requestClient.put('/infra/student/update', data);
  39 +}
  40 +
  41 +/** 删除学生 */
  42 +export function deleteStudent(id: number) {
  43 + return requestClient.delete(`/infra/student/delete?id=${id}`);
  44 +}
  45 +
  46 +/** 批量删除学生 */
  47 +export function deleteStudentList(ids: number[]) {
  48 + return requestClient.delete(`/infra/student/delete-list?ids=${ids.join(',')}`)
  49 +}
  50 +
  51 +/** 导出学生 */
  52 +export function exportStudent(params: any) {
  53 + return requestClient.download('/infra/student/export-excel', { params });
  54 +}
  55 +
  56 +/** 下载学生导入模板 */
  57 +export function importStudentTemplate() {
  58 + return requestClient.download('/infra/student/get-import-template');
  59 +}
  60 +
  61 +/** 导入学生 */
  62 +export function importStudent(data: FormData) {
  63 + return requestClient.post('/infra/student/import', data);
  64 +}
0 65 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/vue/form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/student';
  3 +import type { FormRules } from 'element-plus';
  4 +
  5 +import { useVbenModal } from '@vben/common-ui';
  6 +import { DICT_TYPE } from '@vben/constants';
  7 +import { getDictOptions } from '@vben/hooks';
  8 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  9 +import { ImageUpload, FileUpload } from "#/components/upload";
  10 +import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCheckboxGroup, ElCheckbox, ElDatePicker, ElTreeSelect } from 'element-plus';
  11 +
  12 +import { computed, ref, reactive } from 'vue';
  13 +import { $t } from '#/locales';
  14 +import { getStudent, createStudent, updateStudent } from '#/api/infra/student';
  15 +
  16 +const emit = defineEmits(['success']);
  17 +
  18 +const formRef = ref();
  19 +const formData = ref<Partial<StudentApi.Student>>({
  20 + id: undefined,
  21 + name: undefined,
  22 + description: undefined,
  23 + birthday: undefined,
  24 + sex: undefined,
  25 + enabled: undefined,
  26 + avatar: undefined,
  27 + video: undefined,
  28 + memo: undefined,
  29 +});
  30 +const rules = reactive<FormRules>({
  31 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  32 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  33 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  34 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  35 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  36 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  37 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  38 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  39 +});
  40 +const getTitle = computed(() => {
  41 + return formData.value?.id
  42 + ? $t('ui.actionTitle.edit', ['学生'])
  43 + : $t('ui.actionTitle.create', ['学生']);
  44 +});
  45 +
  46 +
  47 +/** 重置表单 */
  48 +const resetForm = () => {
  49 + formData.value = {
  50 + id: undefined,
  51 + name: undefined,
  52 + description: undefined,
  53 + birthday: undefined,
  54 + sex: undefined,
  55 + enabled: undefined,
  56 + avatar: undefined,
  57 + video: undefined,
  58 + memo: undefined,
  59 + };
  60 + formRef.value?.resetFields();
  61 +}
  62 +
  63 +
  64 +const [Modal, modalApi] = useVbenModal({
  65 + async onConfirm() {
  66 + await formRef.value?.validate();
  67 + modalApi.lock();
  68 + // 提交表单
  69 + const data = formData.value as StudentApi.Student;
  70 + try {
  71 + await (formData.value?.id ? updateStudent(data) : createStudent(data));
  72 + // 关闭并提示
  73 + await modalApi.close();
  74 + emit('success');
  75 + ElMessage.success($t('ui.actionMessage.operationSuccess'));
  76 + } finally {
  77 + modalApi.unlock();
  78 + }
  79 + },
  80 + async onOpenChange(isOpen: boolean) {
  81 + if (!isOpen) {
  82 + resetForm()
  83 + return;
  84 + }
  85 + // 加载数据
  86 + let data = modalApi.getData<StudentApi.Student>();
  87 + if (!data) {
  88 + return;
  89 + }
  90 + if (data.id) {
  91 + modalApi.lock();
  92 + try {
  93 + data = await getStudent(data.id);
  94 + } finally {
  95 + modalApi.unlock();
  96 + }
  97 + }
  98 + formData.value = data;
  99 + },
  100 +});
  101 +</script>
  102 +
  103 +<template>
  104 + <Modal :title="getTitle">
  105 + <el-form
  106 + ref="formRef"
  107 + :model="formData"
  108 + :rules="rules"
  109 + label-width="120px"
  110 + label-position="right"
  111 + >
  112 + <el-form-item label="名字" prop="name">
  113 + <el-input v-model="formData.name" placeholder="请输入名字" />
  114 + </el-form-item>
  115 + <el-form-item label="简介" prop="description">
  116 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  117 + </el-form-item>
  118 + <el-form-item label="出生日期" prop="birthday">
  119 + <el-date-picker
  120 + v-model="formData.birthday"
  121 + value-format="x"
  122 + placeholder="选择出生日期"
  123 + />
  124 + </el-form-item>
  125 + <el-form-item label="性别" prop="sex">
  126 + <el-select v-model="formData.sex" placeholder="请选择性别">
  127 + <el-option
  128 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  129 + :key="dict.value"
  130 + :value="dict.value"
  131 + :label="dict.label"
  132 + />
  133 + </el-select>
  134 + </el-form-item>
  135 + <el-form-item label="是否有效" prop="enabled">
  136 + <el-radio-group v-model="formData.enabled">
  137 + <el-radio
  138 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  139 + :key="dict.value"
  140 + :label="dict.value"
  141 + >
  142 + {{ dict.label }}
  143 + </el-radio>
  144 + </el-radio-group>
  145 + </el-form-item>
  146 + <el-form-item label="头像" prop="avatar">
  147 + <ImageUpload v-model="formData.avatar" />
  148 + </el-form-item>
  149 + <el-form-item label="附件" prop="video">
  150 + <FileUpload v-model="formData.video" />
  151 + </el-form-item>
  152 + <el-form-item label="备注" prop="memo">
  153 + <RichTextarea v-model="formData.memo" height="500px" />
  154 + </el-form-item>
  155 + </el-form>
  156 + </Modal>
  157 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/vue/import-form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import { ref } from 'vue';
  3 +
  4 +import { useVbenModal } from '@vben/common-ui';
  5 +import { downloadFileFromBlobPart } from '@vben/utils';
  6 +
  7 +import { ElButton, ElMessage, ElUpload } from 'element-plus';
  8 +
  9 +import { importStudent, importStudentTemplate } from '#/api/infra/demo';
  10 +
  11 +defineOptions({ name: 'StudentImport' });
  12 +
  13 +const emit = defineEmits(['success']);
  14 +const fileRef = ref<File | null>(null);
  15 +
  16 +const [Modal, modalApi] = useVbenModal({
  17 + async onConfirm() {
  18 + if (!fileRef.value) {
  19 + ElMessage.error('请上传文件');
  20 + return;
  21 + }
  22 + modalApi.lock();
  23 + try {
  24 + const formData = new FormData();
  25 + formData.append('file', fileRef.value);
  26 + const response: any = await importStudent(formData);
  27 + const data = response?.data ?? response ?? {};
  28 + let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';';
  29 + if (data.failureRows) {
  30 + Object.keys(data.failureRows).forEach((rowNo) => {
  31 + text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >';
  32 + });
  33 + }
  34 + ElMessage.info(text);
  35 + await modalApi.close();
  36 + emit('success');
  37 + } finally {
  38 + modalApi.unlock();
  39 + }
  40 + },
  41 +});
  42 +
  43 +/** 文件改变 */
  44 +function handleChange(file: any) {
  45 + if (file.raw) {
  46 + fileRef.value = file.raw;
  47 + }
  48 +}
  49 +
  50 +/** 下载导入模板 */
  51 +async function handleDownload() {
  52 + const data = await importStudentTemplate();
  53 + downloadFileFromBlobPart({ fileName: '学生导入模板.xls', source: data });
  54 +}
  55 +</script>
  56 +
  57 +<template>
  58 + <Modal title="导入学生" class="w-1/3">
  59 + <div class="mx-4">
  60 + <ElUpload
  61 + :limit="1"
  62 + accept=".xls,.xlsx"
  63 + :on-change="handleChange"
  64 + :auto-upload="false"
  65 + >
  66 + <ElButton type="primary"> 选择 Excel 文件 </ElButton>
  67 + </ElUpload>
  68 + </div>
  69 + <template #prepend-footer>
  70 + <div class="flex flex-auto items-center">
  71 + <ElButton @click="handleDownload"> 下载导入模板 </ElButton>
  72 + </div>
  73 + </template>
  74 + </Modal>
  75 +</template>
0 76 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/vue/index 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/student';
  3 +
  4 +import { ref, h, reactive, onMounted, nextTick } from 'vue';
  5 +
  6 +import { Page, useVbenModal } from '@vben/common-ui';
  7 +import { DICT_TYPE } from '@vben/constants';
  8 +import { getDictOptions } from '@vben/hooks';
  9 +import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table';
  10 +import { cloneDeep, downloadFileFromBlobPart, formatDateTime } from '@vben/utils';
  11 +import { ElButton, ElMessage, ElLoading, ElTabs, ElTabPane, ElPagination, ElForm, ElFormItem, ElDatePicker, ElSelect, ElOption, ElInput } from 'element-plus';
  12 +import StudentForm from './modules/form.vue';
  13 +import { Download, Plus, RefreshCw, Search, Trash2 } from '@vben/icons';
  14 +import { ContentWrap } from '#/components/content-wrap';
  15 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  16 +
  17 +
  18 +import { $t } from '#/locales';
  19 +import { isEmpty } from '@vben/utils';
  20 +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/student';
  21 +import StudentImport from './modules/import-form.vue';
  22 +
  23 +
  24 +const loading = ref(true) // 列表的加载中
  25 +const list = ref<StudentApi.Student[]>([]) // 列表的数据
  26 +
  27 +const total = ref(0) // 列表的总页数
  28 +const queryParams = reactive({
  29 + pageNo: 1,
  30 + pageSize: 10,
  31 + name: undefined,
  32 + birthday: undefined,
  33 + birthday: undefined,
  34 + sex: undefined,
  35 + enabled: undefined,
  36 + createTime: undefined,
  37 +})
  38 +const queryFormRef = ref() // 搜索的表单
  39 +const exportLoading = ref(false) // 导出的加载中
  40 +
  41 +/** 查询列表 */
  42 +const getList = async () => {
  43 + loading.value = true
  44 + try {
  45 + const params = cloneDeep(queryParams) as any;
  46 + if (params.birthday && Array.isArray(params.birthday)) {
  47 + params.birthday = (params.birthday as string[]).join(',');
  48 + }
  49 + if (params.createTime && Array.isArray(params.createTime)) {
  50 + params.createTime = (params.createTime as string[]).join(',');
  51 + }
  52 + const data = await getStudentPage(params)
  53 + list.value = data.list
  54 + total.value = data.total
  55 + } finally {
  56 + loading.value = false
  57 + }
  58 +}
  59 +
  60 +/** 搜索按钮操作 */
  61 +function handleQuery() {
  62 + queryParams.pageNo = 1
  63 + getList()
  64 +}
  65 +
  66 +/** 重置按钮操作 */
  67 +function resetQuery() {
  68 + queryFormRef.value.resetFields()
  69 + handleQuery()
  70 +}
  71 +
  72 +const [FormModal, formModalApi] = useVbenModal({
  73 + connectedComponent: StudentForm,
  74 + destroyOnClose: true,
  75 +});
  76 +const [ImportFormModal, importFormModalApi] = useVbenModal({
  77 + connectedComponent: StudentImport,
  78 + destroyOnClose: true,
  79 +});
  80 +
  81 +/** 导入学生 */
  82 +function handleImport() {
  83 + importFormModalApi.open();
  84 +}
  85 +
  86 +/** 创建学生 */
  87 +function handleCreate() {
  88 + formModalApi.setData(null).open();
  89 +}
  90 +
  91 +/** 编辑学生 */
  92 +function handleEdit(row: StudentApi.Student) {
  93 + formModalApi.setData(row).open();
  94 +}
  95 +
  96 +
  97 +/** 删除学生 */
  98 +async function handleDelete(row: StudentApi.Student) {
  99 + const loadingInstance = ElLoading.service({
  100 + text: $t('ui.actionMessage.deleting', [row.id]),
  101 + });
  102 + try {
  103 + await deleteStudent(row.id as number);
  104 + ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  105 + await getList();
  106 + } finally {
  107 + loadingInstance.close();
  108 + }
  109 +}
  110 +
  111 +/** 批量删除学生 */
  112 +async function handleDeleteBatch() {
  113 + const loadingInstance = ElLoading.service({
  114 + text: $t('ui.actionMessage.deleting'),
  115 + });
  116 + try {
  117 + await deleteStudentList(checkedIds.value);
  118 + checkedIds.value = [];
  119 + ElMessage.success($t('ui.actionMessage.deleteSuccess'));
  120 + await getList();
  121 + } finally {
  122 + loadingInstance.close();
  123 + }
  124 +}
  125 +
  126 +const checkedIds = ref<number[]>([])
  127 +function handleRowCheckboxChange({
  128 + records,
  129 +}: {
  130 + records: StudentApi.Student[];
  131 +}) {
  132 + checkedIds.value = records.map((item) => item.id!);
  133 +}
  134 +
  135 +/** 导出表格 */
  136 +async function handleExport() {
  137 +try {
  138 + exportLoading.value = true;
  139 + const data = await exportStudent(queryParams);
  140 + downloadFileFromBlobPart({ fileName: '学生.xls', source: data });
  141 +}finally {
  142 + exportLoading.value = false;
  143 +}
  144 +}
  145 +
  146 +
  147 +
  148 +/** 初始化 */
  149 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  150 +onMounted(() => {
  151 + getList();
  152 +});
  153 +</script>
  154 +
  155 +<template>
  156 + <Page auto-content-height>
  157 + <FormModal @success="getList" />
  158 + <ImportFormModal @success="getList" />
  159 +
  160 + <ContentWrap v-if="!hiddenSearchBar">
  161 + <!-- 搜索工作栏 -->
  162 + <el-form
  163 + :model="queryParams"
  164 + ref="queryFormRef"
  165 + inline
  166 + >
  167 + <el-form-item label="名字">
  168 + <el-input
  169 + v-model="queryParams.name"
  170 + placeholder="请输入名字"
  171 + clearable
  172 + @keyup.enter="handleQuery"
  173 + class="!w-[240px]"
  174 + />
  175 + </el-form-item>
  176 + <el-form-item label="出生日期">
  177 + <el-date-picker
  178 + v-model="queryParams.birthday"
  179 + value-format="YYYY-MM-DD"
  180 + placeholder="选择出生日期"
  181 + clearable
  182 + class="!w-[240px]"
  183 + />
  184 + </el-form-item>
  185 + <el-form-item label="性别">
  186 + <el-select
  187 + v-model="queryParams.sex"
  188 + placeholder="请选择性别"
  189 + clearable
  190 + class="!w-[240px]"
  191 + >
  192 + <el-option
  193 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  194 + :key="dict.value"
  195 + :value="dict.value"
  196 + :label="dict.label"
  197 + />
  198 + </el-select>
  199 + </el-form-item>
  200 + <el-form-item label="是否有效">
  201 + <el-select
  202 + v-model="queryParams.enabled"
  203 + placeholder="请选择是否有效"
  204 + clearable
  205 + class="!w-[240px]"
  206 + >
  207 + <el-option
  208 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  209 + :key="dict.value"
  210 + :value="dict.value"
  211 + :label="dict.label"
  212 + />
  213 + </el-select>
  214 + </el-form-item>
  215 + <el-form-item label="创建时间">
  216 + <el-date-picker
  217 + v-model="queryParams.createTime"
  218 + type="daterange"
  219 + value-format="YYYY-MM-DD"
  220 + range-separator="至"
  221 + start-placeholder="开始日期"
  222 + end-placeholder="结束日期"
  223 + class="!w-[240px]"
  224 + />
  225 + </el-form-item>
  226 + <el-form-item>
  227 + <el-button class="ml-2" @click="resetQuery"> 重置 </el-button>
  228 + <el-button class="ml-2" @click="handleQuery" type="primary">
  229 + 搜索
  230 + </el-button>
  231 + </el-form-item>
  232 + </el-form>
  233 + </ContentWrap>
  234 +
  235 + <!-- 列表 -->
  236 + <ContentWrap title="学生">
  237 + <template #extra>
  238 + <TableToolbar
  239 + ref="tableToolbarRef"
  240 + v-model:hidden-search="hiddenSearchBar"
  241 + >
  242 + <el-button
  243 + class="ml-2"
  244 + :icon="h(Plus)"
  245 + type="primary"
  246 + @click="handleCreate"
  247 + v-access:code="['infra:student:create']"
  248 + >
  249 + {{ $t('ui.actionTitle.create', ['学生']) }}
  250 + </el-button>
  251 + <el-button
  252 + class="ml-2"
  253 + type="primary"
  254 + @click="handleImport"
  255 + v-access:code="['infra:student:import']"
  256 + >
  257 + 导入
  258 + </el-button>
  259 + <el-button
  260 + :icon="h(Download)"
  261 + type="primary"
  262 + class="ml-2"
  263 + :loading="exportLoading"
  264 + @click="handleExport"
  265 + v-access:code="['infra:student:export']"
  266 + >
  267 + {{ $t('ui.actionTitle.export') }}
  268 + </el-button>
  269 + <el-button
  270 + :icon="h(Trash2)"
  271 + type="danger"
  272 + class="ml-2"
  273 + :disabled="isEmpty(checkedIds)"
  274 + @click="handleDeleteBatch"
  275 + v-access:code="['infra:student:delete']"
  276 + >
  277 + 批量删除
  278 + </el-button>
  279 + </TableToolbar>
  280 + </template>
  281 + <vxe-table
  282 + ref="tableRef"
  283 + :data="list"
  284 + show-overflow
  285 + :loading="loading"
  286 + @checkboxAll="handleRowCheckboxChange"
  287 + @checkboxChange="handleRowCheckboxChange"
  288 + >
  289 + <vxe-column type="checkbox" width="40"></vxe-column>
  290 + <vxe-column field="id" title="编号" align="center" />
  291 + <vxe-column field="name" title="名字" align="center" />
  292 + <vxe-column field="description" title="简介" align="center" />
  293 + <vxe-column field="birthday" title="出生日期" align="center">
  294 + <template #default="{row}">
  295 + {{formatDateTime(row.birthday)}}
  296 + </template>
  297 + </vxe-column>
  298 + <vxe-column field="sex" title="性别" align="center">
  299 + <template #default="{row}">
  300 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  301 + </template>
  302 + </vxe-column>
  303 + <vxe-column field="enabled" title="是否有效" align="center">
  304 + <template #default="{row}">
  305 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  306 + </template>
  307 + </vxe-column>
  308 + <vxe-column field="avatar" title="头像" align="center" />
  309 + <vxe-column field="video" title="附件" align="center" />
  310 + <vxe-column field="memo" title="备注" align="center" />
  311 + <vxe-column field="createTime" title="创建时间" align="center">
  312 + <template #default="{row}">
  313 + {{formatDateTime(row.createTime)}}
  314 + </template>
  315 + </vxe-column>
  316 + <vxe-column field="operation" title="操作" align="center">
  317 + <template #default="{row}">
  318 + <el-button
  319 + size="small"
  320 + type="primary"
  321 + link
  322 + @click="handleEdit(row as any)"
  323 + v-access:code="['infra:student:update']"
  324 + >
  325 + {{ $t('ui.actionTitle.edit') }}
  326 + </el-button>
  327 + <el-button
  328 + size="small"
  329 + type="danger"
  330 + link
  331 + class="ml-2"
  332 + @click="handleDelete(row as any)"
  333 + v-access:code="['infra:student:delete']"
  334 + >
  335 + {{ $t('ui.actionTitle.delete') }}
  336 + </el-button>
  337 + </template>
  338 + </vxe-column>
  339 + </vxe-table>
  340 + <!-- 分页 -->
  341 + <div class="mt-2 flex justify-end">
  342 + <el-pagination
  343 + :total="total"
  344 + v-model:current-page="queryParams.pageNo"
  345 + v-model:page-size="queryParams.pageSize"
  346 + :page-sizes="[10, 20, 50, 100]"
  347 + layout="total, sizes, prev, pager, next, jumper"
  348 + @size-change="getList"
  349 + @current-change="getList"
  350 + />
  351 + </div>
  352 + </ContentWrap>
  353 + </Page>
  354 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/xml/InfraStudentMapper 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentImportExcelVO",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportExcelVO.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentImportRespVO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportRespVO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentController",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentDO",
  21 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentMapper",
  24 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  25 +}, {
  26 + "contentPath" : "xml/InfraStudentMapper",
  27 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentServiceImpl",
  30 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  31 +}, {
  32 + "contentPath" : "java/InfraStudentService",
  33 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImplTest",
  36 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  37 +}, {
  38 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  39 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  40 +}, {
  41 + "contentPath" : "sql/sql",
  42 + "filePath" : "sql/sql.sql"
  43 +}, {
  44 + "contentPath" : "sql/h2",
  45 + "filePath" : "sql/h2.sql"
  46 +}, {
  47 + "contentPath" : "ts/data",
  48 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/data.ts"
  49 +}, {
  50 + "contentPath" : "vue/index",
  51 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  52 +}, {
  53 + "contentPath" : "vue/form",
  54 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  55 +}, {
  56 + "contentPath" : "vue/import-form",
  57 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/import-form.vue"
  58 +}, {
  59 + "contentPath" : "ts/index",
  60 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  61 +} ]
0 62 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/ErrorCodeConstants_手动操作 0 → 100644
  1 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  2 +// ========== 学生 TODO 补充编号 ==========
  3 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
0 4 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import org.springframework.web.multipart.MultipartFile;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.security.access.prepost.PreAuthorize;
  8 +import io.swagger.v3.oas.annotations.tags.Tag;
  9 +import io.swagger.v3.oas.annotations.Parameter;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +
  12 +import jakarta.validation.constraints.*;
  13 +import jakarta.validation.*;
  14 +import jakarta.servlet.http.*;
  15 +import java.util.*;
  16 +import java.io.IOException;
  17 +
  18 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  19 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  20 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  21 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  25 +
  26 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  27 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
  28 +
  29 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  30 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  31 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  32 +
  33 +@Tag(name = "管理后台 - 学生")
  34 +@RestController
  35 +@RequestMapping("/infra/student")
  36 +@Validated
  37 +public class InfraStudentController {
  38 +
  39 + @Resource
  40 + private InfraStudentService studentService;
  41 +
  42 + @PostMapping("/create")
  43 + @Operation(summary = "创建学生")
  44 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  45 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  46 + return success(studentService.createStudent(createReqVO));
  47 + }
  48 +
  49 + @PutMapping("/update")
  50 + @Operation(summary = "更新学生")
  51 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  52 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  53 + studentService.updateStudent(updateReqVO);
  54 + return success(true);
  55 + }
  56 +
  57 + @DeleteMapping("/delete")
  58 + @Operation(summary = "删除学生")
  59 + @Parameter(name = "id", description = "编号", required = true)
  60 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  61 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  62 + studentService.deleteStudent(id);
  63 + return success(true);
  64 + }
  65 +
  66 + @DeleteMapping("/delete-list")
  67 + @Parameter(name = "ids", description = "编号", required = true)
  68 + @Operation(summary = "批量删除学生")
  69 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  70 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  71 + studentService.deleteStudentListByIds(ids);
  72 + return success(true);
  73 + }
  74 +
  75 + @GetMapping("/get")
  76 + @Operation(summary = "获得学生")
  77 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  78 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  79 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  80 + InfraStudentDO student = studentService.getStudent(id);
  81 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  82 + }
  83 +
  84 + @GetMapping("/page")
  85 + @Operation(summary = "获得学生分页")
  86 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  87 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  88 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  89 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  90 + }
  91 +
  92 + @GetMapping("/export-excel")
  93 + @Operation(summary = "导出学生 Excel")
  94 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  95 + @ApiAccessLog(operateType = EXPORT)
  96 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  97 + HttpServletResponse response) throws IOException {
  98 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  99 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  100 + // 导出 Excel
  101 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  102 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  103 + }
  104 +
  105 + @GetMapping("/get-import-template")
  106 + @Operation(summary = "获得导入学生模板")
  107 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  108 + public void importTemplate(HttpServletResponse response) throws IOException {
  109 + ExcelUtils.write(response, "学生导入模板.xls", "数据",
  110 + InfraStudentImportExcelVO.class, Collections.emptyList());
  111 + }
  112 +
  113 + @PostMapping("/import")
  114 + @Operation(summary = "导入学生")
  115 + @Parameter(name = "file", description = "Excel 文件", required = true)
  116 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  117 + public CommonResult<InfraStudentImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
  118 + List<InfraStudentImportExcelVO> list = ExcelUtils.read(file, InfraStudentImportExcelVO.class);
  119 + return success(studentService.importStudentList(list));
  120 + }
  121 +
  122 +}
0 123 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +
  68 +}
0 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentImportExcelVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelProperty;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Builder;
  6 +import lombok.Data;
  7 +import lombok.NoArgsConstructor;
  8 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  9 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  10 +
  11 +/**
  12 + * 学生 Excel 导入 VO
  13 + */
  14 +@Data
  15 +@Builder
  16 +@AllArgsConstructor
  17 +@NoArgsConstructor
  18 +public class InfraStudentImportExcelVO {
  19 +
  20 + @ExcelProperty("名字")
  21 + private String name;
  22 +
  23 + @ExcelProperty("简介")
  24 + private String description;
  25 +
  26 + @ExcelProperty("出生日期")
  27 + private LocalDateTime birthday;
  28 +
  29 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  30 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  31 + private Integer sex;
  32 +
  33 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  34 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  35 + private Boolean enabled;
  36 +
  37 + @ExcelProperty("头像")
  38 + private String avatar;
  39 +
  40 + @ExcelProperty("附件")
  41 + private String video;
  42 +
  43 + @ExcelProperty("备注")
  44 + private String memo;
  45 +
  46 +}
0 47 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentImportRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Map;
  8 +
  9 +@Schema(description = "管理后台 - 学生导入 Response VO")
  10 +@Data
  11 +@Builder
  12 +public class InfraStudentImportRespVO {
  13 +
  14 + @Schema(description = "创建成功的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  15 + private Integer successCount;
  16 +
  17 + @Schema(description = "导入失败的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Integer failureCount;
  19 +
  20 + @Schema(description = "导入失败的数据集合,key 为行号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
  21 + private Map<Integer, String> failureRows;
  22 +
  23 +}
0 24 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +public class InfraStudentPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "名字", example = "芋头")
  17 + private String name;
  18 +
  19 + @Schema(description = "出生日期")
  20 + private LocalDateTime birthday;
  21 +
  22 + @Schema(description = "性别", example = "1")
  23 + private Integer sex;
  24 +
  25 + @Schema(description = "是否有效", example = "true")
  26 + private Boolean enabled;
  27 +
  28 + @Schema(description = "创建时间")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + private LocalDateTime[] createTime;
  31 +
  32 +}
0 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +import java.time.LocalDateTime;
  8 +import cn.idev.excel.annotation.*;
  9 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  10 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  11 +
  12 +@Schema(description = "管理后台 - 学生 Response VO")
  13 +@Data
  14 +@ExcelIgnoreUnannotated
  15 +public class InfraStudentRespVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + @ExcelProperty("编号")
  19 + private Long id;
  20 +
  21 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  22 + @ExcelProperty("名字")
  23 + private String name;
  24 +
  25 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  26 + @ExcelProperty("简介")
  27 + private String description;
  28 +
  29 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  30 + @ExcelProperty("出生日期")
  31 + private LocalDateTime birthday;
  32 +
  33 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  34 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  35 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  36 + private Integer sex;
  37 +
  38 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  39 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  40 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  41 + private Boolean enabled;
  42 +
  43 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  44 + @ExcelProperty("头像")
  45 + private String avatar;
  46 +
  47 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  48 + @ExcelProperty("附件")
  49 + private String video;
  50 +
  51 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  52 + @ExcelProperty("备注")
  53 + private String memo;
  54 +
  55 + @Schema(description = "创建时间")
  56 + @ExcelProperty("创建时间")
  57 + private LocalDateTime createTime;
  58 +
  59 +}
0 60 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import jakarta.validation.constraints.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  11 +@Data
  12 +public class InfraStudentSaveReqVO {
  13 +
  14 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  15 + private Long id;
  16 +
  17 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  18 + @NotEmpty(message = "名字不能为空")
  19 + private String name;
  20 +
  21 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  22 + @NotEmpty(message = "简介不能为空")
  23 + private String description;
  24 +
  25 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  26 + @NotNull(message = "出生日期不能为空")
  27 + private LocalDateTime birthday;
  28 +
  29 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  30 + @NotNull(message = "性别不能为空")
  31 + private Integer sex;
  32 +
  33 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  34 + @NotNull(message = "是否有效不能为空")
  35 + private Boolean enabled;
  36 +
  37 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  38 + @NotEmpty(message = "头像不能为空")
  39 + private String avatar;
  40 +
  41 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  42 + @NotEmpty(message = "附件不能为空")
  43 + private String video;
  44 +
  45 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  46 + @NotEmpty(message = "备注不能为空")
  47 + private String memo;
  48 +
  49 +}
0 50 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import jakarta.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  9 +
  10 +/**
  11 + * 学生 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface InfraStudentService {
  16 +
  17 + /**
  18 + * 创建学生
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 导入学生
  27 + *
  28 + * @param importList 导入信息
  29 + * @return 导入结果
  30 + */
  31 + InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList);
  32 +
  33 + /**
  34 + * 更新学生
  35 + *
  36 + * @param updateReqVO 更新信息
  37 + */
  38 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
  39 +
  40 + /**
  41 + * 删除学生
  42 + *
  43 + * @param id 编号
  44 + */
  45 + void deleteStudent(Long id);
  46 +
  47 + /**
  48 + * 批量删除学生
  49 + *
  50 + * @param ids 编号
  51 + */
  52 + void deleteStudentListByIds(List<Long> ids);
  53 +
  54 + /**
  55 + * 获得学生
  56 + *
  57 + * @param id 编号
  58 + * @return 学生
  59 + */
  60 + InfraStudentDO getStudent(Long id);
  61 +
  62 + /**
  63 + * 获得学生分页
  64 + *
  65 + * @param pageReqVO 分页查询
  66 + * @return 学生分页
  67 + */
  68 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  69 +
  70 +}
0 71 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import org.springframework.stereotype.Service;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.transaction.annotation.Transactional;
  8 +
  9 +import java.util.*;
  10 +import java.util.concurrent.atomic.AtomicInteger;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  15 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  16 +
  17 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class InfraStudentServiceImpl implements InfraStudentService {
  32 +
  33 + @Resource
  34 + private InfraStudentMapper studentMapper;
  35 +
  36 + @Override
  37 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  38 + // 插入
  39 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  40 + studentMapper.insert(student);
  41 +
  42 + // 返回
  43 + return student.getId();
  44 + }
  45 +
  46 + @Override
  47 + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入
  48 + public InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList) {
  49 + if (CollUtil.isEmpty(importList)) {
  50 + return InfraStudentImportRespVO.builder()
  51 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  52 + }
  53 + // 遍历,逐个创建
  54 + InfraStudentImportRespVO respVO = InfraStudentImportRespVO.builder()
  55 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  56 + AtomicInteger index = new AtomicInteger(1);
  57 + importList.forEach(importItem -> {
  58 + int currentIndex = index.getAndIncrement();
  59 + try {
  60 + createStudent(BeanUtils.toBean(importItem, InfraStudentSaveReqVO.class));
  61 + respVO.setSuccessCount(respVO.getSuccessCount() + 1);
  62 + } catch (Exception ex) {
  63 + respVO.getFailureRows().put(currentIndex, ex.getMessage());
  64 + }
  65 + });
  66 + respVO.setFailureCount(respVO.getFailureRows().size());
  67 + return respVO;
  68 + }
  69 +
  70 + @Override
  71 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  72 + // 校验存在
  73 + validateStudentExists(updateReqVO.getId());
  74 + // 更新
  75 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  76 + studentMapper.updateById(updateObj);
  77 + }
  78 +
  79 + @Override
  80 + public void deleteStudent(Long id) {
  81 + // 校验存在
  82 + validateStudentExists(id);
  83 + // 删除
  84 + studentMapper.deleteById(id);
  85 + }
  86 +
  87 + @Override
  88 + public void deleteStudentListByIds(List<Long> ids) {
  89 + // 删除
  90 + studentMapper.deleteByIds(ids);
  91 + }
  92 +
  93 +
  94 + private void validateStudentExists(Long id) {
  95 + if (studentMapper.selectById(id) == null) {
  96 + throw exception(STUDENT_NOT_EXISTS);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public InfraStudentDO getStudent(Long id) {
  102 + return studentMapper.selectById(id);
  103 + }
  104 +
  105 + @Override
  106 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  107 + return studentMapper.selectPage(pageReqVO);
  108 + }
  109 +
  110 +}
0 111 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +
  6 +import jakarta.annotation.Resource;
  7 +
  8 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  9 +
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  12 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +
  15 +import jakarta.annotation.Resource;
  16 +import org.springframework.context.annotation.Import;
  17 +import java.util.*;
  18 +import java.time.LocalDateTime;
  19 +
  20 +import static cn.hutool.core.util.RandomUtil.*;
  21 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  22 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  27 +import static org.junit.jupiter.api.Assertions.*;
  28 +import static org.mockito.Mockito.*;
  29 +
  30 +/**
  31 + * {@link InfraStudentServiceImpl} 的单元测试类
  32 + *
  33 + * @author 芋道源码
  34 + */
  35 +@Import(InfraStudentServiceImpl.class)
  36 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  37 +
  38 + @Resource
  39 + private InfraStudentServiceImpl studentService;
  40 +
  41 + @Resource
  42 + private InfraStudentMapper studentMapper;
  43 +
  44 + @Test
  45 + public void testCreateStudent_success() {
  46 + // 准备参数
  47 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  48 +
  49 + // 调用
  50 + Long studentId = studentService.createStudent(createReqVO);
  51 + // 断言
  52 + assertNotNull(studentId);
  53 + // 校验记录的属性是否正确
  54 + InfraStudentDO student = studentMapper.selectById(studentId);
  55 + assertPojoEquals(createReqVO, student, "id");
  56 + }
  57 +
  58 + @Test
  59 + public void testUpdateStudent_success() {
  60 + // mock 数据
  61 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  62 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  63 + // 准备参数
  64 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  65 + o.setId(dbStudent.getId()); // 设置更新的 ID
  66 + });
  67 +
  68 + // 调用
  69 + studentService.updateStudent(updateReqVO);
  70 + // 校验是否更新正确
  71 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  72 + assertPojoEquals(updateReqVO, student);
  73 + }
  74 +
  75 + @Test
  76 + public void testUpdateStudent_notExists() {
  77 + // 准备参数
  78 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  79 +
  80 + // 调用, 并断言异常
  81 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  82 + }
  83 +
  84 + @Test
  85 + public void testDeleteStudent_success() {
  86 + // mock 数据
  87 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  88 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  89 + // 准备参数
  90 + Long id = dbStudent.getId();
  91 +
  92 + // 调用
  93 + studentService.deleteStudent(id);
  94 + // 校验数据不存在了
  95 + assertNull(studentMapper.selectById(id));
  96 + }
  97 +
  98 + @Test
  99 + public void testDeleteStudent_notExists() {
  100 + // 准备参数
  101 + Long id = randomLongId();
  102 +
  103 + // 调用, 并断言异常
  104 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  105 + }
  106 +
  107 + @Test
  108 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  109 + public void testGetStudentPage() {
  110 + // mock 数据
  111 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  112 + o.setName(null);
  113 + o.setBirthday(null);
  114 + o.setSex(null);
  115 + o.setEnabled(null);
  116 + o.setCreateTime(null);
  117 + });
  118 + studentMapper.insert(dbStudent);
  119 + // 测试 name 不匹配
  120 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  121 + // 测试 birthday 不匹配
  122 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  123 + // 测试 sex 不匹配
  124 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  125 + // 测试 enabled 不匹配
  126 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  127 + // 测试 createTime 不匹配
  128 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  129 + // 准备参数
  130 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  131 + reqVO.setName(null);
  132 + reqVO.setBirthday(null);
  133 + reqVO.setSex(null);
  134 + reqVO.setEnabled(null);
  135 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  136 +
  137 + // 调用
  138 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  139 + // 断言
  140 + assertEquals(1, pageResult.getTotal());
  141 + assertEquals(1, pageResult.getList().size());
  142 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  143 + }
  144 +
  145 +}
0 146 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +SELECT @parentId := LAST_INSERT_ID();
  13 +
  14 +-- 按钮 SQL
  15 +INSERT INTO system_menu(
  16 + name, permission, type, sort, parent_id,
  17 + path, icon, component, status
  18 +)
  19 +VALUES (
  20 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  21 + '', '', '', 0
  22 +);
  23 +INSERT INTO system_menu(
  24 + name, permission, type, sort, parent_id,
  25 + path, icon, component, status
  26 +)
  27 +VALUES (
  28 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  29 + '', '', '', 0
  30 +);
  31 +INSERT INTO system_menu(
  32 + name, permission, type, sort, parent_id,
  33 + path, icon, component, status
  34 +)
  35 +VALUES (
  36 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  37 + '', '', '', 0
  38 +);
  39 +INSERT INTO system_menu(
  40 + name, permission, type, sort, parent_id,
  41 + path, icon, component, status
  42 +)
  43 +VALUES (
  44 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  45 + '', '', '', 0
  46 +);
  47 +INSERT INTO system_menu(
  48 + name, permission, type, sort, parent_id,
  49 + path, icon, component, status
  50 +)
  51 +VALUES (
  52 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  53 + '', '', '', 0
  54 +);
  55 +INSERT INTO system_menu(
  56 + name, permission, type, sort, parent_id,
  57 + path, icon, component, status
  58 +)
  59 +VALUES (
  60 + '学生导入', 'infra:student:import', 3, 6, @parentId,
  61 + '', '', '', 0
  62 +);
0 63 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/ts/data 0 → 100644
  1 +import type { VbenFormSchema } from '#/adapter/form';
  2 +import type { VxeTableGridOptions } from '#/adapter/vxe-table';
  3 +import type { InfraStudentApi } from '#/api/infra/demo';
  4 +
  5 +import { DICT_TYPE } from '@vben/constants';
  6 +import { getDictOptions } from '@vben/hooks';
  7 +
  8 +import { getRangePickerDefaultProps } from '#/utils';
  9 +
  10 +/** 新增/修改的表单 */
  11 +export function useFormSchema(): VbenFormSchema[] {
  12 + return [
  13 + {
  14 + fieldName: 'id',
  15 + component: 'Input',
  16 + dependencies: {
  17 + triggerFields: [''],
  18 + show: () => false,
  19 + },
  20 + },
  21 + {
  22 + fieldName: 'name',
  23 + label: '名字',
  24 + rules: 'required',
  25 + component: 'Input',
  26 + componentProps: {
  27 + placeholder: '请输入名字',
  28 + },
  29 + },
  30 + {
  31 + fieldName: 'description',
  32 + label: '简介',
  33 + rules: 'required',
  34 + component: 'Textarea',
  35 + componentProps: {
  36 + placeholder: '请输入简介',
  37 + },
  38 + },
  39 + {
  40 + fieldName: 'birthday',
  41 + label: '出生日期',
  42 + rules: 'required',
  43 + component: 'DatePicker',
  44 + componentProps: {
  45 + showTime: true,
  46 + format: 'YYYY-MM-DD HH:mm:ss',
  47 + valueFormat: 'x',
  48 + class: '!w-full',
  49 + },
  50 + },
  51 + {
  52 + fieldName: 'sex',
  53 + label: '性别',
  54 + rules: 'required',
  55 + component: 'Select',
  56 + componentProps: {
  57 + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'),
  58 + placeholder: '请选择性别',
  59 + },
  60 + },
  61 + {
  62 + fieldName: 'enabled',
  63 + label: '是否有效',
  64 + rules: 'required',
  65 + component: 'RadioGroup',
  66 + componentProps: {
  67 + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
  68 + buttonStyle: 'solid',
  69 + optionType: 'button',
  70 + },
  71 + },
  72 + {
  73 + fieldName: 'avatar',
  74 + label: '头像',
  75 + rules: 'required',
  76 + component: 'ImageUpload',
  77 + },
  78 + {
  79 + fieldName: 'video',
  80 + label: '附件',
  81 + rules: 'required',
  82 + component: 'FileUpload',
  83 + },
  84 + {
  85 + fieldName: 'memo',
  86 + label: '备注',
  87 + rules: 'required',
  88 + component: 'RichTextarea',
  89 + },
  90 + ];
  91 +}
  92 +
  93 +/** 导入的表单 */
  94 +export function useImportFormSchema(): VbenFormSchema[] {
  95 + return [
  96 + {
  97 + fieldName: 'file',
  98 + label: '学生数据',
  99 + component: 'Upload',
  100 + rules: 'required',
  101 + help: '仅允许导入 xls、xlsx 格式文件',
  102 + },
  103 + ];
  104 +}
  105 +
  106 +/** 列表的搜索表单 */
  107 +export function useGridFormSchema(): VbenFormSchema[] {
  108 + return [
  109 + {
  110 + fieldName: 'name',
  111 + label: '名字',
  112 + component: 'Input',
  113 + componentProps: {
  114 + clearable: true,
  115 + placeholder: '请输入名字',
  116 + },
  117 + },
  118 + {
  119 + fieldName: 'birthday',
  120 + label: '出生日期',
  121 + component: 'RangePicker',
  122 + componentProps: {
  123 + ...getRangePickerDefaultProps(),
  124 + clearable: true,
  125 + },
  126 + },
  127 + {
  128 + fieldName: 'sex',
  129 + label: '性别',
  130 + component: 'Select',
  131 + componentProps: {
  132 + clearable: true,
  133 + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'),
  134 + placeholder: '请选择性别',
  135 + },
  136 + },
  137 + {
  138 + fieldName: 'enabled',
  139 + label: '是否有效',
  140 + component: 'Select',
  141 + componentProps: {
  142 + clearable: true,
  143 + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'),
  144 + placeholder: '请选择是否有效',
  145 + },
  146 + },
  147 + {
  148 + fieldName: 'createTime',
  149 + label: '创建时间',
  150 + component: 'RangePicker',
  151 + componentProps: {
  152 + ...getRangePickerDefaultProps(),
  153 + clearable: true,
  154 + },
  155 + },
  156 + ];
  157 +}
  158 +
  159 +/** 列表的字段 */
  160 +export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>['columns'] {
  161 + return [
  162 + { type: 'checkbox', width: 40 },
  163 + {
  164 + field: 'id',
  165 + title: '编号',
  166 + minWidth: 120,
  167 + cellRender: {
  168 + name: 'CellDict',
  169 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  170 + },
  171 + },
  172 + {
  173 + field: 'name',
  174 + title: '名字',
  175 + minWidth: 120,
  176 + cellRender: {
  177 + name: 'CellDict',
  178 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  179 + },
  180 + },
  181 + {
  182 + field: 'description',
  183 + title: '简介',
  184 + minWidth: 120,
  185 + cellRender: {
  186 + name: 'CellDict',
  187 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  188 + },
  189 + },
  190 + {
  191 + field: 'birthday',
  192 + title: '出生日期',
  193 + minWidth: 120,
  194 + formatter: 'formatDateTime',
  195 + },
  196 + {
  197 + field: 'sex',
  198 + title: '性别',
  199 + minWidth: 120,
  200 + cellRender: {
  201 + name: 'CellDict',
  202 + props: { type: DICT_TYPE.SYSTEM_USER_SEX },
  203 + },
  204 + },
  205 + {
  206 + field: 'enabled',
  207 + title: '是否有效',
  208 + minWidth: 120,
  209 + cellRender: {
  210 + name: 'CellDict',
  211 + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING },
  212 + },
  213 + },
  214 + {
  215 + field: 'avatar',
  216 + title: '头像',
  217 + minWidth: 120,
  218 + cellRender: {
  219 + name: 'CellDict',
  220 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  221 + },
  222 + },
  223 + {
  224 + field: 'video',
  225 + title: '附件',
  226 + minWidth: 120,
  227 + cellRender: {
  228 + name: 'CellDict',
  229 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  230 + },
  231 + },
  232 + {
  233 + field: 'memo',
  234 + title: '备注',
  235 + minWidth: 120,
  236 + cellRender: {
  237 + name: 'CellDict',
  238 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  239 + },
  240 + },
  241 + {
  242 + field: 'createTime',
  243 + title: '创建时间',
  244 + minWidth: 120,
  245 + formatter: 'formatDateTime',
  246 + },
  247 + {
  248 + title: '操作',
  249 + width: 200,
  250 + fixed: 'right',
  251 + slots: { default: 'actions' },
  252 + },
  253 + ];
  254 +}
  255 +
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/ts/index 0 → 100644
  1 +import type { PageParam, PageResult } from '@vben/request';
  2 +import type { Dayjs } from 'dayjs';
  3 +
  4 +import { requestClient } from '#/api/request';
  5 +
  6 +export namespace InfraStudentApi {
  7 + /** 学生信息 */
  8 + export interface Student {
  9 + id: number; // 编号
  10 + name?: string; // 名字
  11 + description?: string; // 简介
  12 + birthday?: string | Dayjs; // 出生日期
  13 + sex?: number; // 性别
  14 + enabled?: boolean; // 是否有效
  15 + avatar?: string; // 头像
  16 + video?: string; // 附件
  17 + memo?: string; // 备注
  18 + }
  19 +}
  20 +
  21 +/** 查询学生分页 */
  22 +export function getStudentPage(params: PageParam) {
  23 + return requestClient.get<PageResult<InfraStudentApi.Student>>(
  24 + '/infra/student/page',
  25 + { params },
  26 + );
  27 +}
  28 +
  29 +/** 查询学生详情 */
  30 +export function getStudent(id: number) {
  31 + return requestClient.get<InfraStudentApi.Student>(
  32 + `/infra/student/get?id=${id}`,
  33 + );
  34 +}
  35 +
  36 +/** 新增学生 */
  37 +export function createStudent(data: InfraStudentApi.Student) {
  38 + return requestClient.post('/infra/student/create', data);
  39 +}
  40 +
  41 +/** 修改学生 */
  42 +export function updateStudent(data: InfraStudentApi.Student) {
  43 + return requestClient.put('/infra/student/update', data);
  44 +}
  45 +
  46 +/** 删除学生 */
  47 +export function deleteStudent(id: number) {
  48 + return requestClient.delete(`/infra/student/delete?id=${id}`);
  49 +}
  50 +
  51 +/** 批量删除学生 */
  52 +export function deleteStudentList(ids: number[]) {
  53 + return requestClient.delete(
  54 + `/infra/student/delete-list?ids=${ids.join(',')}`,
  55 + );
  56 +}
  57 +
  58 +/** 导出学生 */
  59 +export function exportStudent(params: any) {
  60 + return requestClient.download('/infra/student/export-excel', { params });
  61 +}
  62 +
  63 +/** 下载学生导入模板 */
  64 +export function importStudentTemplate() {
  65 + return requestClient.download('/infra/student/get-import-template');
  66 +}
  67 +
  68 +/** 导入学生 */
  69 +export function importStudent(file: File) {
  70 + return requestClient.upload('/infra/student/import', { file });
  71 +}
0 72 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/vue/form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { InfraStudentApi } from '#/api/infra/demo';
  3 +
  4 +import { computed, ref } from 'vue';
  5 +
  6 +import { useVbenModal } from '@vben/common-ui';
  7 +
  8 +import { ElMessage } from 'element-plus';
  9 +
  10 +import { useVbenForm } from '#/adapter/form';
  11 +import { createStudent, getStudent, updateStudent } from '#/api/infra/demo';
  12 +import { $t } from '#/locales';
  13 +
  14 +import { useFormSchema } from '../data';
  15 +
  16 +const emit = defineEmits(['success']);
  17 +const formData = ref<InfraStudentApi.Student>();
  18 +const getTitle = computed(() => {
  19 + return formData.value?.id
  20 + ? $t('ui.actionTitle.edit', ['学生'])
  21 + : $t('ui.actionTitle.create', ['学生']);
  22 +});
  23 +
  24 +const [Form, formApi] = useVbenForm({
  25 + commonConfig: {
  26 + componentProps: {
  27 + class: 'w-full',
  28 + },
  29 + formItemClass: 'col-span-2',
  30 + labelWidth: 80,
  31 + },
  32 + layout: 'horizontal',
  33 + schema: useFormSchema(),
  34 + showDefaultActions: false,
  35 +});
  36 +
  37 +const [Modal, modalApi] = useVbenModal({
  38 + async onConfirm() {
  39 + const { valid } = await formApi.validate();
  40 + if (!valid) {
  41 + return;
  42 + }
  43 + modalApi.lock();
  44 + // 提交表单
  45 + const data = (await formApi.getValues()) as InfraStudentApi.Student;
  46 + try {
  47 + await (formData.value?.id ? updateStudent(data) : createStudent(data));
  48 + // 关闭并提示
  49 + await modalApi.close();
  50 + emit('success');
  51 + ElMessage.success($t('ui.actionMessage.operationSuccess'));
  52 + } finally {
  53 + modalApi.unlock();
  54 + }
  55 + },
  56 + async onOpenChange(isOpen: boolean) {
  57 + if (!isOpen) {
  58 + formData.value = undefined;
  59 + return;
  60 + }
  61 + // 加载数据
  62 + const data = modalApi.getData<InfraStudentApi.Student>();
  63 + if (!data || !data.id) {
  64 + return;
  65 + }
  66 + modalApi.lock();
  67 + try {
  68 + formData.value = await getStudent(data.id);
  69 + // 设置到 values
  70 + await formApi.setValues(formData.value);
  71 + } finally {
  72 + modalApi.unlock();
  73 + }
  74 + },
  75 +});
  76 +</script>
  77 +
  78 +<template>
  79 + <Modal :title="getTitle">
  80 + <Form class="mx-4" />
  81 + </Modal>
  82 +</template>
0 83 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/vue/import-form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import { useVbenModal } from '@vben/common-ui';
  3 +import { downloadFileFromBlobPart } from '@vben/utils';
  4 +
  5 +import { ElButton, ElMessage, ElUpload } from 'element-plus';
  6 +
  7 +import { useVbenForm } from '#/adapter/form';
  8 +import { importStudent, importStudentTemplate } from '#/api/infra/demo';
  9 +import { $t } from '#/locales';
  10 +
  11 +import { useImportFormSchema } from '../data';
  12 +
  13 +const emit = defineEmits(['success']);
  14 +
  15 +const [Form, formApi] = useVbenForm({
  16 + commonConfig: {
  17 + formItemClass: 'col-span-2',
  18 + labelWidth: 120,
  19 + },
  20 + layout: 'horizontal',
  21 + schema: useImportFormSchema(),
  22 + showDefaultActions: false,
  23 +});
  24 +
  25 +const [Modal, modalApi] = useVbenModal({
  26 + async onConfirm() {
  27 + const { valid } = await formApi.validate();
  28 + if (!valid) {
  29 + return;
  30 + }
  31 + modalApi.lock();
  32 + // 提交表单
  33 + const data = await formApi.getValues();
  34 + try {
  35 + await importStudent(data.file);
  36 + // 关闭并提示
  37 + await modalApi.close();
  38 + emit('success');
  39 + ElMessage.success($t('ui.actionMessage.operationSuccess'));
  40 + } finally {
  41 + modalApi.unlock();
  42 + }
  43 + },
  44 +});
  45 +
  46 +/** 文件改变时 */
  47 +function handleChange(file: any) {
  48 + if (file.raw) {
  49 + formApi.setFieldValue('file', file.raw);
  50 + }
  51 +}
  52 +
  53 +/** 下载模板 */
  54 +async function handleDownload() {
  55 + const data = await importStudentTemplate();
  56 + downloadFileFromBlobPart({ fileName: '学生导入模板.xls', source: data });
  57 +}
  58 +</script>
  59 +
  60 +<template>
  61 + <Modal title="导入学生" class="w-1/3">
  62 + <Form class="mx-4">
  63 + <template #file>
  64 + <div class="w-full">
  65 + <ElUpload
  66 + :limit="1"
  67 + accept=".xls,.xlsx"
  68 + :on-change="handleChange"
  69 + :auto-upload="false"
  70 + >
  71 + <ElButton type="primary"> 选择 Excel 文件 </ElButton>
  72 + </ElUpload>
  73 + </div>
  74 + </template>
  75 + </Form>
  76 + <template #prepend-footer>
  77 + <div class="flex flex-auto items-center">
  78 + <ElButton @click="handleDownload"> 下载导入模板 </ElButton>
  79 + </div>
  80 + </template>
  81 + </Modal>
  82 +</template>
0 83 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/vue/index 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { VxeTableGridOptions } from '#/adapter/vxe-table';
  3 +import type { InfraStudentApi } from '#/api/infra/demo';
  4 +
  5 +import { ref } from 'vue';
  6 +
  7 +import { confirm, Page, useVbenModal } from '@vben/common-ui';
  8 +import { downloadFileFromBlobPart, isEmpty } from '@vben/utils';
  9 +
  10 +import { ElLoading, ElMessage } from 'element-plus';
  11 +
  12 +import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
  13 +import {
  14 + deleteStudent,
  15 + deleteStudentList,
  16 + exportStudent,
  17 + getStudentPage,
  18 +} from '#/api/infra/demo';
  19 +import StudentImport from './modules/import-form.vue';
  20 +import { $t } from '#/locales';
  21 +
  22 +import { useGridColumns, useGridFormSchema } from './data';
  23 +import Form from './modules/form.vue';
  24 +
  25 +const [FormModal, formModalApi] = useVbenModal({
  26 + connectedComponent: Form,
  27 + destroyOnClose: true,
  28 +});
  29 +const [ImportFormModal, importFormModalApi] = useVbenModal({
  30 + connectedComponent: StudentImport,
  31 + destroyOnClose: true,
  32 +});
  33 +
  34 +/** 导入学生 */
  35 +function handleImport() {
  36 + importFormModalApi.open();
  37 +}
  38 +
  39 +/** 刷新表格 */
  40 +function handleRefresh() {
  41 + gridApi.query();
  42 +}
  43 +
  44 +/** 创建学生 */
  45 +function handleCreate() {
  46 + formModalApi.setData(null).open();
  47 +}
  48 +
  49 +/** 编辑学生 */
  50 +function handleEdit(row: InfraStudentApi.Student) {
  51 + formModalApi.setData(row).open();
  52 +}
  53 +
  54 +/** 删除学生 */
  55 +async function handleDelete(row: InfraStudentApi.Student) {
  56 + const loadingInstance = ElLoading.service({
  57 + text: $t('ui.actionMessage.deleting', [row.id]),
  58 + });
  59 + try {
  60 + await deleteStudent(row.id!);
  61 + ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  62 + handleRefresh();
  63 + } finally {
  64 + loadingInstance.close();
  65 + }
  66 +}
  67 +
  68 +/** 批量删除学生 */
  69 +async function handleDeleteBatch() {
  70 + await confirm($t('ui.actionMessage.deleteBatchConfirm'));
  71 + const loadingInstance = ElLoading.service({
  72 + text: $t('ui.actionMessage.deletingBatch'),
  73 + });
  74 + try {
  75 + await deleteStudentList(checkedIds.value);
  76 + checkedIds.value = [];
  77 + ElMessage.success($t('ui.actionMessage.deleteSuccess'));
  78 + handleRefresh();
  79 + } finally {
  80 + loadingInstance.close();
  81 + }
  82 +}
  83 +
  84 +const checkedIds = ref<number[]>([]);
  85 +function handleRowCheckboxChange({
  86 + records,
  87 +}: {
  88 + records: InfraStudentApi.Student[];
  89 +}) {
  90 + checkedIds.value = records.map((item) => item.id!);
  91 +}
  92 +
  93 +/** 导出表格 */
  94 +async function handleExport() {
  95 + const data = await exportStudent(await gridApi.formApi.getValues());
  96 + downloadFileFromBlobPart({ fileName: '学生.xls', source: data });
  97 +}
  98 +
  99 +
  100 +const [Grid, gridApi] = useVbenVxeGrid({
  101 + formOptions: {
  102 + schema: useGridFormSchema(),
  103 + },
  104 + gridOptions: {
  105 + columns: useGridColumns(),
  106 + height: 'auto',
  107 + keepSource: true,
  108 + proxyConfig: {
  109 + ajax: {
  110 + query: async ({ page }, formValues) => {
  111 + return await getStudentPage({
  112 + pageNo: page.currentPage,
  113 + pageSize: page.pageSize,
  114 + ...formValues,
  115 + });
  116 + },
  117 + },
  118 + },
  119 + rowConfig: {
  120 + keyField: 'id',
  121 + isHover: true,
  122 + },
  123 + toolbarConfig: {
  124 + refresh: true,
  125 + search: true,
  126 + },
  127 + } as VxeTableGridOptions<InfraStudentApi.Student>,
  128 + gridEvents: {
  129 + checkboxAll: handleRowCheckboxChange,
  130 + checkboxChange: handleRowCheckboxChange,
  131 + },
  132 +});
  133 +</script>
  134 +
  135 +<template>
  136 + <Page auto-content-height>
  137 + <FormModal @success="handleRefresh" />
  138 + <ImportFormModal @success="handleRefresh" />
  139 + <Grid table-title="学生列表">
  140 + <template #toolbar-tools>
  141 + <TableAction
  142 + :actions="[
  143 + {
  144 + label: $t('ui.actionTitle.create', ['学生']),
  145 + type: 'primary',
  146 + icon: ACTION_ICON.ADD,
  147 + auth: ['infra:student:create'],
  148 + onClick: handleCreate,
  149 + },
  150 + {
  151 + label: '导入',
  152 + type: 'primary',
  153 + auth: ['infra:student:import'],
  154 + onClick: handleImport,
  155 + },
  156 + {
  157 + label: $t('ui.actionTitle.export'),
  158 + type: 'primary',
  159 + icon: ACTION_ICON.DOWNLOAD,
  160 + auth: ['infra:student:export'],
  161 + onClick: handleExport,
  162 + },
  163 + {
  164 + label: $t('ui.actionTitle.deleteBatch'),
  165 + type: 'danger',
  166 + icon: ACTION_ICON.DELETE,
  167 + auth: ['infra:student:delete'],
  168 + disabled: isEmpty(checkedIds),
  169 + onClick: handleDeleteBatch,
  170 + },
  171 + ]"
  172 + />
  173 + </template>
  174 + <template #actions="{ row }">
  175 + <TableAction
  176 + :actions="[
  177 + {
  178 + label: $t('common.edit'),
  179 + type: 'primary',
  180 + link: true,
  181 + icon: ACTION_ICON.EDIT,
  182 + auth: ['infra:student:update'],
  183 + onClick: handleEdit.bind(null, row),
  184 + },
  185 + {
  186 + label: $t('common.delete'),
  187 + type: 'danger',
  188 + link: true,
  189 + icon: ACTION_ICON.DELETE,
  190 + auth: ['infra:student:delete'],
  191 + popConfirm: {
  192 + title: $t('ui.actionMessage.deleteConfirm', [row.id]),
  193 + confirm: handleDelete.bind(null, row),
  194 + },
  195 + },
  196 + ]"
  197 + />
  198 + </template>
  199 + </Grid>
  200 + </Page>
  201 +</template>
0 202 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/xml/InfraStudentMapper 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentImportExcelVO",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportExcelVO.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentImportRespVO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentImportRespVO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentController",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentDO",
  21 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentMapper",
  24 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  25 +}, {
  26 + "contentPath" : "xml/InfraStudentMapper",
  27 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentServiceImpl",
  30 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  31 +}, {
  32 + "contentPath" : "java/InfraStudentService",
  33 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImplTest",
  36 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  37 +}, {
  38 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  39 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  40 +}, {
  41 + "contentPath" : "sql/sql",
  42 + "filePath" : "sql/sql.sql"
  43 +}, {
  44 + "contentPath" : "sql/h2",
  45 + "filePath" : "sql/h2.sql"
  46 +}, {
  47 + "contentPath" : "vue/index",
  48 + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/index.vue"
  49 +}, {
  50 + "contentPath" : "js/index",
  51 + "filePath" : "yudao-ui-admin-vue2/src/api/infra/demo/index.js"
  52 +}, {
  53 + "contentPath" : "vue/StudentForm",
  54 + "filePath" : "yudao-ui-admin-vue2/src/views/infra/demo/StudentForm.vue"
  55 +} ]
0 56 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/ErrorCodeConstants_手动操作 0 → 100644
  1 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  2 +// ========== 学生 TODO 补充编号 ==========
  3 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
0 4 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import org.springframework.web.multipart.MultipartFile;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.security.access.prepost.PreAuthorize;
  8 +import io.swagger.v3.oas.annotations.tags.Tag;
  9 +import io.swagger.v3.oas.annotations.Parameter;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +
  12 +import jakarta.validation.constraints.*;
  13 +import jakarta.validation.*;
  14 +import jakarta.servlet.http.*;
  15 +import java.util.*;
  16 +import java.io.IOException;
  17 +
  18 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  19 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  20 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  21 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  25 +
  26 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  27 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
  28 +
  29 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  30 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  31 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  32 +
  33 +@Tag(name = "管理后台 - 学生")
  34 +@RestController
  35 +@RequestMapping("/infra/student")
  36 +@Validated
  37 +public class InfraStudentController {
  38 +
  39 + @Resource
  40 + private InfraStudentService studentService;
  41 +
  42 + @PostMapping("/create")
  43 + @Operation(summary = "创建学生")
  44 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  45 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  46 + return success(studentService.createStudent(createReqVO));
  47 + }
  48 +
  49 + @PutMapping("/update")
  50 + @Operation(summary = "更新学生")
  51 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  52 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  53 + studentService.updateStudent(updateReqVO);
  54 + return success(true);
  55 + }
  56 +
  57 + @DeleteMapping("/delete")
  58 + @Operation(summary = "删除学生")
  59 + @Parameter(name = "id", description = "编号", required = true)
  60 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  61 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  62 + studentService.deleteStudent(id);
  63 + return success(true);
  64 + }
  65 +
  66 + @DeleteMapping("/delete-list")
  67 + @Parameter(name = "ids", description = "编号", required = true)
  68 + @Operation(summary = "批量删除学生")
  69 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  70 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  71 + studentService.deleteStudentListByIds(ids);
  72 + return success(true);
  73 + }
  74 +
  75 + @GetMapping("/get")
  76 + @Operation(summary = "获得学生")
  77 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  78 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  79 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  80 + InfraStudentDO student = studentService.getStudent(id);
  81 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  82 + }
  83 +
  84 + @GetMapping("/page")
  85 + @Operation(summary = "获得学生分页")
  86 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  87 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  88 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  89 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  90 + }
  91 +
  92 + @GetMapping("/export-excel")
  93 + @Operation(summary = "导出学生 Excel")
  94 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  95 + @ApiAccessLog(operateType = EXPORT)
  96 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  97 + HttpServletResponse response) throws IOException {
  98 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  99 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  100 + // 导出 Excel
  101 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  102 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  103 + }
  104 +
  105 + @GetMapping("/get-import-template")
  106 + @Operation(summary = "获得导入学生模板")
  107 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  108 + public void importTemplate(HttpServletResponse response) throws IOException {
  109 + ExcelUtils.write(response, "学生导入模板.xls", "数据",
  110 + InfraStudentImportExcelVO.class, Collections.emptyList());
  111 + }
  112 +
  113 + @PostMapping("/import")
  114 + @Operation(summary = "导入学生")
  115 + @Parameter(name = "file", description = "Excel 文件", required = true)
  116 + @PreAuthorize("@ss.hasPermission('infra:student:import')")
  117 + public CommonResult<InfraStudentImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
  118 + List<InfraStudentImportExcelVO> list = ExcelUtils.read(file, InfraStudentImportExcelVO.class);
  119 + return success(studentService.importStudentList(list));
  120 + }
  121 +
  122 +}
0 123 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +
  68 +}
0 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentImportExcelVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelProperty;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Builder;
  6 +import lombok.Data;
  7 +import lombok.NoArgsConstructor;
  8 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  9 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  10 +
  11 +/**
  12 + * 学生 Excel 导入 VO
  13 + */
  14 +@Data
  15 +@Builder
  16 +@AllArgsConstructor
  17 +@NoArgsConstructor
  18 +public class InfraStudentImportExcelVO {
  19 +
  20 + @ExcelProperty("名字")
  21 + private String name;
  22 +
  23 + @ExcelProperty("简介")
  24 + private String description;
  25 +
  26 + @ExcelProperty("出生日期")
  27 + private LocalDateTime birthday;
  28 +
  29 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  30 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  31 + private Integer sex;
  32 +
  33 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  34 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  35 + private Boolean enabled;
  36 +
  37 + @ExcelProperty("头像")
  38 + private String avatar;
  39 +
  40 + @ExcelProperty("附件")
  41 + private String video;
  42 +
  43 + @ExcelProperty("备注")
  44 + private String memo;
  45 +
  46 +}
0 47 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentImportRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Map;
  8 +
  9 +@Schema(description = "管理后台 - 学生导入 Response VO")
  10 +@Data
  11 +@Builder
  12 +public class InfraStudentImportRespVO {
  13 +
  14 + @Schema(description = "创建成功的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  15 + private Integer successCount;
  16 +
  17 + @Schema(description = "导入失败的数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  18 + private Integer failureCount;
  19 +
  20 + @Schema(description = "导入失败的数据集合,key 为行号,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
  21 + private Map<Integer, String> failureRows;
  22 +
  23 +}
0 24 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +public class InfraStudentPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "名字", example = "芋头")
  17 + private String name;
  18 +
  19 + @Schema(description = "出生日期")
  20 + private LocalDateTime birthday;
  21 +
  22 + @Schema(description = "性别", example = "1")
  23 + private Integer sex;
  24 +
  25 + @Schema(description = "是否有效", example = "true")
  26 + private Boolean enabled;
  27 +
  28 + @Schema(description = "创建时间")
  29 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  30 + private LocalDateTime[] createTime;
  31 +
  32 +}
0 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +import java.time.LocalDateTime;
  8 +import cn.idev.excel.annotation.*;
  9 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  10 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  11 +
  12 +@Schema(description = "管理后台 - 学生 Response VO")
  13 +@Data
  14 +@ExcelIgnoreUnannotated
  15 +public class InfraStudentRespVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + @ExcelProperty("编号")
  19 + private Long id;
  20 +
  21 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  22 + @ExcelProperty("名字")
  23 + private String name;
  24 +
  25 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  26 + @ExcelProperty("简介")
  27 + private String description;
  28 +
  29 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  30 + @ExcelProperty("出生日期")
  31 + private LocalDateTime birthday;
  32 +
  33 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  34 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  35 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  36 + private Integer sex;
  37 +
  38 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  39 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  40 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  41 + private Boolean enabled;
  42 +
  43 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  44 + @ExcelProperty("头像")
  45 + private String avatar;
  46 +
  47 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  48 + @ExcelProperty("附件")
  49 + private String video;
  50 +
  51 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  52 + @ExcelProperty("备注")
  53 + private String memo;
  54 +
  55 + @Schema(description = "创建时间")
  56 + @ExcelProperty("创建时间")
  57 + private LocalDateTime createTime;
  58 +
  59 +}
0 60 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import jakarta.validation.constraints.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  11 +@Data
  12 +public class InfraStudentSaveReqVO {
  13 +
  14 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  15 + private Long id;
  16 +
  17 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  18 + @NotEmpty(message = "名字不能为空")
  19 + private String name;
  20 +
  21 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  22 + @NotEmpty(message = "简介不能为空")
  23 + private String description;
  24 +
  25 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  26 + @NotNull(message = "出生日期不能为空")
  27 + private LocalDateTime birthday;
  28 +
  29 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  30 + @NotNull(message = "性别不能为空")
  31 + private Integer sex;
  32 +
  33 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  34 + @NotNull(message = "是否有效不能为空")
  35 + private Boolean enabled;
  36 +
  37 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  38 + @NotEmpty(message = "头像不能为空")
  39 + private String avatar;
  40 +
  41 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  42 + @NotEmpty(message = "附件不能为空")
  43 + private String video;
  44 +
  45 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  46 + @NotEmpty(message = "备注不能为空")
  47 + private String memo;
  48 +
  49 +}
0 50 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import jakarta.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  9 +
  10 +/**
  11 + * 学生 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface InfraStudentService {
  16 +
  17 + /**
  18 + * 创建学生
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 导入学生
  27 + *
  28 + * @param importList 导入信息
  29 + * @return 导入结果
  30 + */
  31 + InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList);
  32 +
  33 + /**
  34 + * 更新学生
  35 + *
  36 + * @param updateReqVO 更新信息
  37 + */
  38 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
  39 +
  40 + /**
  41 + * 删除学生
  42 + *
  43 + * @param id 编号
  44 + */
  45 + void deleteStudent(Long id);
  46 +
  47 + /**
  48 + * 批量删除学生
  49 + *
  50 + * @param ids 编号
  51 + */
  52 + void deleteStudentListByIds(List<Long> ids);
  53 +
  54 + /**
  55 + * 获得学生
  56 + *
  57 + * @param id 编号
  58 + * @return 学生
  59 + */
  60 + InfraStudentDO getStudent(Long id);
  61 +
  62 + /**
  63 + * 获得学生分页
  64 + *
  65 + * @param pageReqVO 分页查询
  66 + * @return 学生分页
  67 + */
  68 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  69 +
  70 +}
0 71 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import org.springframework.stereotype.Service;
  5 +import jakarta.annotation.Resource;
  6 +import org.springframework.validation.annotation.Validated;
  7 +import org.springframework.transaction.annotation.Transactional;
  8 +
  9 +import java.util.*;
  10 +import java.util.concurrent.atomic.AtomicInteger;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  15 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  16 +
  17 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  18 +
  19 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class InfraStudentServiceImpl implements InfraStudentService {
  32 +
  33 + @Resource
  34 + private InfraStudentMapper studentMapper;
  35 +
  36 + @Override
  37 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  38 + // 插入
  39 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  40 + studentMapper.insert(student);
  41 +
  42 + // 返回
  43 + return student.getId();
  44 + }
  45 +
  46 + @Override
  47 + @Transactional(rollbackFor = Exception.class) // 添加事务,异常则回滚所有导入
  48 + public InfraStudentImportRespVO importStudentList(List<InfraStudentImportExcelVO> importList) {
  49 + if (CollUtil.isEmpty(importList)) {
  50 + return InfraStudentImportRespVO.builder()
  51 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  52 + }
  53 + // 遍历,逐个创建
  54 + InfraStudentImportRespVO respVO = InfraStudentImportRespVO.builder()
  55 + .successCount(0).failureCount(0).failureRows(new LinkedHashMap<>()).build();
  56 + AtomicInteger index = new AtomicInteger(1);
  57 + importList.forEach(importItem -> {
  58 + int currentIndex = index.getAndIncrement();
  59 + try {
  60 + createStudent(BeanUtils.toBean(importItem, InfraStudentSaveReqVO.class));
  61 + respVO.setSuccessCount(respVO.getSuccessCount() + 1);
  62 + } catch (Exception ex) {
  63 + respVO.getFailureRows().put(currentIndex, ex.getMessage());
  64 + }
  65 + });
  66 + respVO.setFailureCount(respVO.getFailureRows().size());
  67 + return respVO;
  68 + }
  69 +
  70 + @Override
  71 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  72 + // 校验存在
  73 + validateStudentExists(updateReqVO.getId());
  74 + // 更新
  75 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  76 + studentMapper.updateById(updateObj);
  77 + }
  78 +
  79 + @Override
  80 + public void deleteStudent(Long id) {
  81 + // 校验存在
  82 + validateStudentExists(id);
  83 + // 删除
  84 + studentMapper.deleteById(id);
  85 + }
  86 +
  87 + @Override
  88 + public void deleteStudentListByIds(List<Long> ids) {
  89 + // 删除
  90 + studentMapper.deleteByIds(ids);
  91 + }
  92 +
  93 +
  94 + private void validateStudentExists(Long id) {
  95 + if (studentMapper.selectById(id) == null) {
  96 + throw exception(STUDENT_NOT_EXISTS);
  97 + }
  98 + }
  99 +
  100 + @Override
  101 + public InfraStudentDO getStudent(Long id) {
  102 + return studentMapper.selectById(id);
  103 + }
  104 +
  105 + @Override
  106 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  107 + return studentMapper.selectPage(pageReqVO);
  108 + }
  109 +
  110 +}
0 111 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +
  6 +import jakarta.annotation.Resource;
  7 +
  8 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  9 +
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  12 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +
  15 +import jakarta.annotation.Resource;
  16 +import org.springframework.context.annotation.Import;
  17 +import java.util.*;
  18 +import java.time.LocalDateTime;
  19 +
  20 +import static cn.hutool.core.util.RandomUtil.*;
  21 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  22 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  24 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  27 +import static org.junit.jupiter.api.Assertions.*;
  28 +import static org.mockito.Mockito.*;
  29 +
  30 +/**
  31 + * {@link InfraStudentServiceImpl} 的单元测试类
  32 + *
  33 + * @author 芋道源码
  34 + */
  35 +@Import(InfraStudentServiceImpl.class)
  36 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  37 +
  38 + @Resource
  39 + private InfraStudentServiceImpl studentService;
  40 +
  41 + @Resource
  42 + private InfraStudentMapper studentMapper;
  43 +
  44 + @Test
  45 + public void testCreateStudent_success() {
  46 + // 准备参数
  47 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  48 +
  49 + // 调用
  50 + Long studentId = studentService.createStudent(createReqVO);
  51 + // 断言
  52 + assertNotNull(studentId);
  53 + // 校验记录的属性是否正确
  54 + InfraStudentDO student = studentMapper.selectById(studentId);
  55 + assertPojoEquals(createReqVO, student, "id");
  56 + }
  57 +
  58 + @Test
  59 + public void testUpdateStudent_success() {
  60 + // mock 数据
  61 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  62 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  63 + // 准备参数
  64 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  65 + o.setId(dbStudent.getId()); // 设置更新的 ID
  66 + });
  67 +
  68 + // 调用
  69 + studentService.updateStudent(updateReqVO);
  70 + // 校验是否更新正确
  71 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  72 + assertPojoEquals(updateReqVO, student);
  73 + }
  74 +
  75 + @Test
  76 + public void testUpdateStudent_notExists() {
  77 + // 准备参数
  78 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  79 +
  80 + // 调用, 并断言异常
  81 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  82 + }
  83 +
  84 + @Test
  85 + public void testDeleteStudent_success() {
  86 + // mock 数据
  87 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  88 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  89 + // 准备参数
  90 + Long id = dbStudent.getId();
  91 +
  92 + // 调用
  93 + studentService.deleteStudent(id);
  94 + // 校验数据不存在了
  95 + assertNull(studentMapper.selectById(id));
  96 + }
  97 +
  98 + @Test
  99 + public void testDeleteStudent_notExists() {
  100 + // 准备参数
  101 + Long id = randomLongId();
  102 +
  103 + // 调用, 并断言异常
  104 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  105 + }
  106 +
  107 + @Test
  108 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  109 + public void testGetStudentPage() {
  110 + // mock 数据
  111 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  112 + o.setName(null);
  113 + o.setBirthday(null);
  114 + o.setSex(null);
  115 + o.setEnabled(null);
  116 + o.setCreateTime(null);
  117 + });
  118 + studentMapper.insert(dbStudent);
  119 + // 测试 name 不匹配
  120 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  121 + // 测试 birthday 不匹配
  122 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  123 + // 测试 sex 不匹配
  124 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  125 + // 测试 enabled 不匹配
  126 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  127 + // 测试 createTime 不匹配
  128 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  129 + // 准备参数
  130 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  131 + reqVO.setName(null);
  132 + reqVO.setBirthday(null);
  133 + reqVO.setSex(null);
  134 + reqVO.setEnabled(null);
  135 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  136 +
  137 + // 调用
  138 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  139 + // 断言
  140 + assertEquals(1, pageResult.getTotal());
  141 + assertEquals(1, pageResult.getList().size());
  142 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  143 + }
  144 +
  145 +}
0 146 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/js/index 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 创建学生
  4 +export function createStudent(data) {
  5 + return request({
  6 + url: '/infra/student/create',
  7 + method: 'post',
  8 + data: data
  9 + })
  10 +}
  11 +
  12 +// 更新学生
  13 +export function updateStudent(data) {
  14 + return request({
  15 + url: '/infra/student/update',
  16 + method: 'put',
  17 + data: data
  18 + })
  19 +}
  20 +
  21 +// 删除学生
  22 +export function deleteStudent(id) {
  23 + return request({
  24 + url: '/infra/student/delete?id=' + id,
  25 + method: 'delete'
  26 + })
  27 +}
  28 +
  29 +/** 批量删除学生 */
  30 +export function deleteStudentList(ids) {
  31 + return request({
  32 + url: `/infra/student/delete-list?ids=${ids.join(',')}`,
  33 + method: 'delete'
  34 + })
  35 +}
  36 +
  37 +// 获得学生
  38 +export function getStudent(id) {
  39 + return request({
  40 + url: '/infra/student/get?id=' + id,
  41 + method: 'get'
  42 + })
  43 +}
  44 +
  45 +// 获得学生分页
  46 +export function getStudentPage(params) {
  47 + return request({
  48 + url: '/infra/student/page',
  49 + method: 'get',
  50 + params
  51 + })
  52 +}
  53 +// 导出学生 Excel
  54 +export function exportStudentExcel(params) {
  55 + return request({
  56 + url: '/infra/student/export-excel',
  57 + method: 'get',
  58 + params,
  59 + responseType: 'blob'
  60 + })
  61 +}
  62 +
  63 +// 下载学生导入模板
  64 +export function importStudentTemplate() {
  65 + return request({
  66 + url: '/infra/student/get-import-template',
  67 + method: 'get',
  68 + responseType: 'blob'
  69 + })
  70 +}
  71 +
  72 +// 导入学生
  73 +export function importStudent(data) {
  74 + return request({
  75 + url: '/infra/student/import',
  76 + method: 'post',
  77 + data
  78 + })
  79 +}
0 80 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +SELECT @parentId := LAST_INSERT_ID();
  13 +
  14 +-- 按钮 SQL
  15 +INSERT INTO system_menu(
  16 + name, permission, type, sort, parent_id,
  17 + path, icon, component, status
  18 +)
  19 +VALUES (
  20 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  21 + '', '', '', 0
  22 +);
  23 +INSERT INTO system_menu(
  24 + name, permission, type, sort, parent_id,
  25 + path, icon, component, status
  26 +)
  27 +VALUES (
  28 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  29 + '', '', '', 0
  30 +);
  31 +INSERT INTO system_menu(
  32 + name, permission, type, sort, parent_id,
  33 + path, icon, component, status
  34 +)
  35 +VALUES (
  36 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  37 + '', '', '', 0
  38 +);
  39 +INSERT INTO system_menu(
  40 + name, permission, type, sort, parent_id,
  41 + path, icon, component, status
  42 +)
  43 +VALUES (
  44 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  45 + '', '', '', 0
  46 +);
  47 +INSERT INTO system_menu(
  48 + name, permission, type, sort, parent_id,
  49 + path, icon, component, status
  50 +)
  51 +VALUES (
  52 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  53 + '', '', '', 0
  54 +);
  55 +INSERT INTO system_menu(
  56 + name, permission, type, sort, parent_id,
  57 + path, icon, component, status
  58 +)
  59 +VALUES (
  60 + '学生导入', 'infra:student:import', 3, 6, @parentId,
  61 + '', '', '', 0
  62 +);
0 63 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/vue/StudentForm 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 + <!-- 对话框(添加 / 修改) -->
  4 + <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="45%" v-dialogDrag append-to-body>
  5 + <el-form ref="formRef" :model="formData" :rules="formRules" v-loading="formLoading" label-width="100px">
  6 + <el-form-item label="名字" prop="name">
  7 + <el-input v-model="formData.name" placeholder="请输入名字" />
  8 + </el-form-item>
  9 + <el-form-item label="简介" prop="description">
  10 + <el-input v-model="formData.description" type="textarea" placeholder="请输入内容" />
  11 + </el-form-item>
  12 + <el-form-item label="出生日期" prop="birthday">
  13 + <el-date-picker clearable v-model="formData.birthday" type="date" value-format="timestamp" placeholder="选择出生日期" />
  14 + </el-form-item>
  15 + <el-form-item label="性别" prop="sex">
  16 + <el-select v-model="formData.sex" placeholder="请选择性别">
  17 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_USER_SEX)"
  18 + :key="dict.value" :label="dict.label" :value="parseInt(dict.value)" />
  19 + </el-select>
  20 + </el-form-item>
  21 + <el-form-item label="是否有效" prop="enabled">
  22 + <el-radio-group v-model="formData.enabled">
  23 + <el-radio v-for="dict in this.getDictDatas(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  24 + :key="dict.value" :label="dict.value">{{dict.label}}</el-radio>
  25 + </el-radio-group>
  26 + </el-form-item>
  27 + <el-form-item label="头像">
  28 + <ImageUpload v-model="formData.avatar"/>
  29 + </el-form-item>
  30 + <el-form-item label="附件">
  31 + <FileUpload v-model="formData.video"/>
  32 + </el-form-item>
  33 + <el-form-item label="备注">
  34 + <Editor v-model="formData.memo" :min-height="192"/>
  35 + </el-form-item>
  36 + </el-form>
  37 + <div slot="footer" class="dialog-footer">
  38 + <el-button type="primary" @click="submitForm" :disabled="formLoading">确 定</el-button>
  39 + <el-button @click="dialogVisible = false">取 消</el-button>
  40 + </div>
  41 + </el-dialog>
  42 + </div>
  43 +</template>
  44 +
  45 +<script>
  46 + import * as StudentApi from '@/api/infra/demo';
  47 + import ImageUpload from '@/components/ImageUpload';
  48 + import FileUpload from '@/components/FileUpload';
  49 + import Editor from '@/components/Editor';
  50 + export default {
  51 + name: "StudentForm",
  52 + components: {
  53 + ImageUpload,
  54 + FileUpload,
  55 + Editor,
  56 + },
  57 + data() {
  58 + return {
  59 + // 弹出层标题
  60 + dialogTitle: "",
  61 + // 是否显示弹出层
  62 + dialogVisible: false,
  63 + // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  64 + formLoading: false,
  65 + // 表单参数
  66 + formData: {
  67 + id: undefined,
  68 + name: undefined,
  69 + description: undefined,
  70 + birthday: undefined,
  71 + sex: undefined,
  72 + enabled: undefined,
  73 + avatar: undefined,
  74 + video: undefined,
  75 + memo: undefined,
  76 + },
  77 + // 表单校验
  78 + formRules: {
  79 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  80 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  81 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  82 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  83 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  84 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  85 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  86 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  87 + },
  88 + };
  89 + },
  90 + methods: {
  91 + /** 打开弹窗 */
  92 + async open(id) {
  93 + this.dialogVisible = true;
  94 + this.reset();
  95 + // 修改时,设置数据
  96 + if (id) {
  97 + this.formLoading = true;
  98 + try {
  99 + const res = await StudentApi.getStudent(id);
  100 + this.formData = res.data;
  101 + this.title = "修改学生";
  102 + } finally {
  103 + this.formLoading = false;
  104 + }
  105 + }
  106 + this.title = "新增学生";
  107 + },
  108 + /** 提交按钮 */
  109 + async submitForm() {
  110 + // 校验主表
  111 + await this.$refs["formRef"].validate();
  112 + this.formLoading = true;
  113 + try {
  114 + const data = this.formData;
  115 + // 修改的提交
  116 + if (data.id) {
  117 + await StudentApi.updateStudent(data);
  118 + this.$modal.msgSuccess("修改成功");
  119 + this.dialogVisible = false;
  120 + this.$emit('success');
  121 + return;
  122 + }
  123 + // 添加的提交
  124 + await StudentApi.createStudent(data);
  125 + this.$modal.msgSuccess("新增成功");
  126 + this.dialogVisible = false;
  127 + this.$emit('success');
  128 + } finally {
  129 + this.formLoading = false;
  130 + }
  131 + },
  132 + /** 表单重置 */
  133 + reset() {
  134 + this.formData = {
  135 + id: undefined,
  136 + name: undefined,
  137 + description: undefined,
  138 + birthday: undefined,
  139 + sex: undefined,
  140 + enabled: undefined,
  141 + avatar: undefined,
  142 + video: undefined,
  143 + memo: undefined,
  144 + };
  145 + this.resetForm("formRef");
  146 + }
  147 + }
  148 + };
  149 +</script>
... ...
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/vue/index 0 → 100644
  1 +<template>
  2 + <div class="app-container">
  3 + <!-- 搜索工作栏 -->
  4 + <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  5 + <el-form-item label="名字" prop="name">
  6 + <el-input v-model="queryParams.name" placeholder="请输入名字" clearable @keyup.enter.native="handleQuery"/>
  7 + </el-form-item>
  8 + <el-form-item label="出生日期" prop="birthday">
  9 + <el-date-picker clearable v-model="queryParams.birthday" type="date" value-format="yyyy-MM-dd" placeholder="选择出生日期" />
  10 + </el-form-item>
  11 + <el-form-item label="性别" prop="sex">
  12 + <el-select v-model="queryParams.sex" placeholder="请选择性别" clearable size="small">
  13 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.SYSTEM_USER_SEX)"
  14 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  15 + </el-select>
  16 + </el-form-item>
  17 + <el-form-item label="是否有效" prop="enabled">
  18 + <el-select v-model="queryParams.enabled" placeholder="请选择是否有效" clearable size="small">
  19 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  20 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  21 + </el-select>
  22 + </el-form-item>
  23 + <el-form-item label="创建时间" prop="createTime">
  24 + <el-date-picker v-model="queryParams.createTime" style="width: 240px" value-format="yyyy-MM-dd HH:mm:ss" type="daterange"
  25 + range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期" :default-time="['00:00:00', '23:59:59']" />
  26 + </el-form-item>
  27 + <el-form-item>
  28 + <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  29 + <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
  30 + </el-form-item>
  31 + </el-form>
  32 +
  33 + <!-- 操作工具栏 -->
  34 + <el-row :gutter="10" class="mb8">
  35 + <el-col :span="1.5">
  36 + <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="openForm(undefined)"
  37 + v-hasPermi="['infra:student:create']">新增</el-button>
  38 + </el-col>
  39 + <el-col :span="1.5">
  40 + <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport"
  41 + :loading="importLoading" v-hasPermi="['infra:student:import']">导入</el-button>
  42 + </el-col>
  43 + <el-col :span="1.5">
  44 + <el-button type="info" plain icon="el-icon-document" size="mini" @click="handleImportTemplate"
  45 + v-hasPermi="['infra:student:import']">导入模板</el-button>
  46 + </el-col>
  47 + <el-col :span="1.5">
  48 + <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
  49 + v-hasPermi="['infra:student:export']">导出</el-button>
  50 + </el-col>
  51 + <el-col :span="1.5">
  52 + <el-button
  53 + type="danger"
  54 + plain
  55 + icon="el-icon-delete"
  56 + size="mini"
  57 + :disabled="isEmpty(checkedIds)"
  58 + @click="handleDeleteBatch"
  59 + v-hasPermi="['infra:student:delete']"
  60 + >
  61 + 批量删除
  62 + </el-button>
  63 + </el-col>
  64 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  65 + </el-row>
  66 + <input ref="importFileRef" type="file" style="display: none" accept=".xls,.xlsx" @change="handleImportFileChange" />
  67 +
  68 + <el-table
  69 + v-loading="loading"
  70 + :data="list"
  71 + :stripe="true"
  72 + :show-overflow-tooltip="true"
  73 + @selection-change="handleRowCheckboxChange"
  74 + >
  75 + <el-table-column type="selection" width="55" />
  76 + <el-table-column label="编号" align="center" prop="id">
  77 + <template v-slot="scope">
  78 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.id" />
  79 + </template>
  80 + </el-table-column>
  81 + <el-table-column label="名字" align="center" prop="name">
  82 + <template v-slot="scope">
  83 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.name" />
  84 + </template>
  85 + </el-table-column>
  86 + <el-table-column label="简介" align="center" prop="description">
  87 + <template v-slot="scope">
  88 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.description" />
  89 + </template>
  90 + </el-table-column>
  91 + <el-table-column label="出生日期" align="center" prop="birthday" width="180">
  92 + <template v-slot="scope">
  93 + <span>{{ parseTime(scope.row.birthday) }}</span>
  94 + </template>
  95 + </el-table-column>
  96 + <el-table-column label="性别" align="center" prop="sex">
  97 + <template v-slot="scope">
  98 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  99 + </template>
  100 + </el-table-column>
  101 + <el-table-column label="是否有效" align="center" prop="enabled">
  102 + <template v-slot="scope">
  103 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  104 + </template>
  105 + </el-table-column>
  106 + <el-table-column label="头像" align="center" prop="avatar">
  107 + <template v-slot="scope">
  108 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.avatar" />
  109 + </template>
  110 + </el-table-column>
  111 + <el-table-column label="附件" align="center" prop="video">
  112 + <template v-slot="scope">
  113 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.video" />
  114 + </template>
  115 + </el-table-column>
  116 + <el-table-column label="备注" align="center" prop="memo">
  117 + <template v-slot="scope">
  118 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.memo" />
  119 + </template>
  120 + </el-table-column>
  121 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  122 + <template v-slot="scope">
  123 + <span>{{ parseTime(scope.row.createTime) }}</span>
  124 + </template>
  125 + </el-table-column>
  126 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  127 + <template v-slot="scope">
  128 + <el-button size="mini" type="text" icon="el-icon-edit" @click="openForm(scope.row.id)"
  129 + v-hasPermi="['infra:student:update']">修改</el-button>
  130 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  131 + v-hasPermi="['infra:student:delete']">删除</el-button>
  132 + </template>
  133 + </el-table-column>
  134 + </el-table>
  135 + <!-- 分页组件 -->
  136 + <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  137 + @pagination="getList"/>
  138 + <!-- 对话框(添加 / 修改) -->
  139 + <StudentForm ref="formRef" @success="getList" />
  140 + </div>
  141 +</template>
  142 +
  143 +<script>
  144 +import * as StudentApi from '@/api/infra/demo';
  145 +import StudentForm from './StudentForm.vue';
  146 +export default {
  147 + name: "Student",
  148 + components: {
  149 + StudentForm
  150 + },
  151 + data() {
  152 + return {
  153 + // 遮罩层
  154 + loading: true,
  155 + // 导出遮罩层
  156 + exportLoading: false,
  157 + // 导入遮罩层
  158 + importLoading: false,
  159 + // 显示搜索条件
  160 + showSearch: true,
  161 + // 总条数
  162 + total: 0,
  163 + // 学生列表
  164 + list: [],
  165 + // 是否展开,默认全部展开
  166 + isExpandAll: true,
  167 + // 重新渲染表格状态
  168 + refreshTable: true,
  169 + // 选中行
  170 + currentRow: {},
  171 + checkedIds: [],
  172 + // 查询参数
  173 + queryParams: {
  174 + pageNo: 1,
  175 + pageSize: 10,
  176 + name: null,
  177 + birthday: null,
  178 + sex: null,
  179 + enabled: null,
  180 + createTime: [],
  181 + },
  182 + };
  183 + },
  184 + created() {
  185 + this.getList();
  186 + },
  187 + methods: {
  188 + /** 查询列表 */
  189 + async getList() {
  190 + try {
  191 + this.loading = true;
  192 + const res = await StudentApi.getStudentPage(this.queryParams);
  193 + this.list = res.data.list;
  194 + this.total = res.data.total;
  195 + } finally {
  196 + this.loading = false;
  197 + }
  198 + },
  199 + /** 搜索按钮操作 */
  200 + handleQuery() {
  201 + this.queryParams.pageNo = 1;
  202 + this.getList();
  203 + },
  204 + /** 重置按钮操作 */
  205 + resetQuery() {
  206 + this.resetForm("queryForm");
  207 + this.handleQuery();
  208 + },
  209 + /** 添加/修改操作 */
  210 + openForm(id) {
  211 + this.$refs["formRef"].open(id);
  212 + },
  213 + /** 导入按钮操作 */
  214 + handleImport() {
  215 + this.$refs.importFileRef && this.$refs.importFileRef.click();
  216 + },
  217 + /** 导入模板下载 */
  218 + async handleImportTemplate() {
  219 + const data = await StudentApi.importStudentTemplate();
  220 + this.$download.excel(data, '学生导入模板.xls');
  221 + },
  222 + /** 导入文件变更 */
  223 + async handleImportFileChange(event) {
  224 + const target = event.target;
  225 + const file = target.files && target.files[0];
  226 + if (!file) {
  227 + return;
  228 + }
  229 + this.importLoading = true;
  230 + try {
  231 + const formData = new FormData();
  232 + formData.append('file', file);
  233 + const res = await StudentApi.importStudent(formData);
  234 + const data = res.data || res;
  235 + let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';';
  236 + if (data.failureRows) {
  237 + Object.keys(data.failureRows).forEach((rowNo) => {
  238 + text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >';
  239 + });
  240 + }
  241 + await this.$alert(text, '学生导入结果', { dangerouslyUseHTMLString: true });
  242 + await this.getList();
  243 + } catch {
  244 + } finally {
  245 + target.value = '';
  246 + this.importLoading = false;
  247 + }
  248 + },
  249 + /** 删除按钮操作 */
  250 + async handleDelete(row) {
  251 + const id = row.id;
  252 + await this.$modal.confirm('是否确认删除学生编号为"' + id + '"的数据项?')
  253 + try {
  254 + await StudentApi.deleteStudent(id);
  255 + await this.getList();
  256 + this.$modal.msgSuccess("删除成功");
  257 + } catch {}
  258 + },
  259 + /** 批量删除学生 */
  260 + async handleDeleteBatch() {
  261 + await this.$modal.confirm('是否确认删除?')
  262 + try {
  263 + await StudentApi.deleteStudentList(this.checkedIds);
  264 + this.checkedIds = [];
  265 + await this.getList();
  266 + this.$modal.msgSuccess("删除成功");
  267 + } catch {}
  268 + },
  269 + handleRowCheckboxChange(records) {
  270 + this.checkedIds = records.map((item) => item.id);
  271 + },
  272 + /** 导出按钮操作 */
  273 + async handleExport() {
  274 + await this.$modal.confirm('是否确认导出所有学生数据项?');
  275 + try {
  276 + this.exportLoading = true;
  277 + const data = await StudentApi.exportStudentExcel(this.queryParams);
  278 + this.$download.excel(data, '学生.xls');
  279 + } catch {
  280 + } finally {
  281 + this.exportLoading = false;
  282 + }
  283 + },
  284 + }
  285 +};
  286 +</script>
... ...