Commit 46305340853e9b19a990eaee446e790b0f186dd3

Authored by YunaiV
1 parent 48eb3e33

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

Showing 669 changed files with 43171 additions and 2028 deletions

Too many changes.

To preserve performance only 100 of 669 files are displayed.

yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/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/InfraStudentController",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentDO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentContactDO",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentTeacherDO",
  21 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.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" : "java/InfraStudentContactMapper",
  27 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentTeacherMapper",
  30 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java"
  31 +}, {
  32 + "contentPath" : "xml/InfraStudentMapper",
  33 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImpl",
  36 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  37 +}, {
  38 + "contentPath" : "java/InfraStudentService",
  39 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  40 +}, {
  41 + "contentPath" : "java/InfraStudentServiceImplTest",
  42 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  43 +}, {
  44 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  45 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  46 +}, {
  47 + "contentPath" : "sql/sql",
  48 + "filePath" : "sql/sql.sql"
  49 +}, {
  50 + "contentPath" : "sql/h2",
  51 + "filePath" : "sql/h2.sql"
  52 +}, {
  53 + "contentPath" : "vue/index",
  54 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  55 +}, {
  56 + "contentPath" : "vue/form",
  57 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  58 +}, {
  59 + "contentPath" : "ts/index",
  60 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  61 +}, {
  62 + "contentPath" : "vue/student-contact-form",
  63 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-contact-form.vue"
  64 +}, {
  65 + "contentPath" : "vue/student-teacher-form",
  66 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-teacher-form.vue"
  67 +}, {
  68 + "contentPath" : "vue/student-contact-list",
  69 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-contact-list.vue"
  70 +}, {
  71 + "contentPath" : "vue/student-teacher-list",
  72 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-teacher-list.vue"
  73 +} ]
0 74 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/ErrorCodeConstants_手动操作 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/ErrorCodeConstants_手动操作
1   -// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
2   -// ========== 学生 TODO 补充编号 ==========
3   -ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
4   -ErrorCode STUDENT_CONTACT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生联系人不存在");
5   -ErrorCode STUDENT_TEACHER_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生班主任不存在");
6   -ErrorCode STUDENT_TEACHER_EXISTS = new ErrorCode(TODO 补充编号, "学生班主任已存在");
7 1 \ No newline at end of file
  2 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  3 +// ========== 学生 TODO 补充编号 ==========
  4 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
  5 +ErrorCode STUDENT_CONTACT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生联系人不存在");
  6 +ErrorCode STUDENT_TEACHER_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生班主任不存在");
  7 +ErrorCode STUDENT_TEACHER_EXISTS = new ErrorCode(TODO 补充编号, "学生班主任已存在");
8 8 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentContactDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentContactDO
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentContactMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentContactMapper
... ... @@ -27,4 +27,8 @@ public interface InfraStudentContactMapper extends BaseMapperX<InfraStudentConta
27 27 return delete(InfraStudentContactDO::getStudentId, studentId);
28 28 }
29 29  
  30 + default int deleteByStudentIds(List<Long> studentIds) {
  31 + return deleteBatch(InfraStudentContactDO::getStudentId, studentIds);
  32 + }
  33 +
30 34 }
31 35 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentController renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentController
1 1 package cn.iocoder.yudao.module.infra.controller.admin.demo;
2 2  
3 3 import org.springframework.web.bind.annotation.*;
4   -import javax.annotation.Resource;
  4 +import jakarta.annotation.Resource;
5 5 import org.springframework.validation.annotation.Validated;
6 6 import org.springframework.security.access.prepost.PreAuthorize;
7 7 import io.swagger.v3.oas.annotations.tags.Tag;
8 8 import io.swagger.v3.oas.annotations.Parameter;
9 9 import io.swagger.v3.oas.annotations.Operation;
10 10  
11   -import javax.validation.constraints.*;
12   -import javax.validation.*;
13   -import javax.servlet.http.*;
  11 +import jakarta.validation.constraints.*;
  12 +import jakarta.validation.*;
  13 +import jakarta.servlet.http.*;
14 14 import java.util.*;
15 15 import java.io.IOException;
16 16  
... ... @@ -22,8 +22,8 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 22  
23 23 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
24 24  
25   -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
26   -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  25 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  26 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
27 27  
28 28 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
29 29 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
... ... @@ -64,6 +64,15 @@ public class InfraStudentController {
64 64 return success(true);
65 65 }
66 66  
  67 + @DeleteMapping("/delete-list")
  68 + @Parameter(name = "ids", description = "编号", required = true)
  69 + @Operation(summary = "批量删除学生")
  70 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  71 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  72 + studentService.deleteStudentListByIds(ids);
  73 + return success(true);
  74 + }
  75 +
67 76 @GetMapping("/get")
68 77 @Operation(summary = "获得学生")
69 78 @Parameter(name = "id", description = "编号", required = true, example = "1024")
... ... @@ -84,7 +93,7 @@ public class InfraStudentController {
84 93 @GetMapping("/export-excel")
85 94 @Operation(summary = "导出学生 Excel")
86 95 @PreAuthorize("@ss.hasPermission('infra:student:export')")
87   - @OperateLog(type = EXPORT)
  96 + @ApiAccessLog(operateType = EXPORT)
88 97 public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
89 98 HttpServletResponse response) throws IOException {
90 99 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
... ... @@ -129,6 +138,15 @@ public class InfraStudentController {
129 138 return success(true);
130 139 }
131 140  
  141 + @DeleteMapping("/student-contact/delete-list")
  142 + @Parameter(name = "ids", description = "编号", required = true)
  143 + @Operation(summary = "批量删除学生联系人")
  144 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  145 + public CommonResult<Boolean> deleteStudentContactList(@RequestParam("ids") List<Long> ids) {
  146 + studentService.deleteStudentContactListByIds(ids);
  147 + return success(true);
  148 + }
  149 +
132 150 @GetMapping("/student-contact/get")
133 151 @Operation(summary = "获得学生联系人")
134 152 @Parameter(name = "id", description = "编号", required = true)
... ... @@ -172,6 +190,15 @@ public class InfraStudentController {
172 190 return success(true);
173 191 }
174 192  
  193 + @DeleteMapping("/student-teacher/delete-list")
  194 + @Parameter(name = "ids", description = "编号", required = true)
  195 + @Operation(summary = "批量删除学生班主任")
  196 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  197 + public CommonResult<Boolean> deleteStudentTeacherList(@RequestParam("ids") List<Long> ids) {
  198 + studentService.deleteStudentTeacherListByIds(ids);
  199 + return success(true);
  200 + }
  201 +
175 202 @GetMapping("/student-teacher/get")
176 203 @Operation(summary = "获得学生班主任")
177 204 @Parameter(name = "id", description = "编号", required = true)
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentDO
... ... @@ -64,4 +64,5 @@ public class InfraStudentDO extends BaseDO {
64 64 */
65 65 private String memo;
66 66  
  67 +
67 68 }
68 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentMapper
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentPageReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentPageReqVO
... ... @@ -11,8 +11,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
11 11  
12 12 @Schema(description = "管理后台 - 学生分页 Request VO")
13 13 @Data
14   -@EqualsAndHashCode(callSuper = true)
15   -@ToString(callSuper = true)
16 14 public class InfraStudentPageReqVO extends PageParam {
17 15  
18 16 @Schema(description = "名字", example = "芋头")
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentRespVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentRespVO
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import java.util.*;
7 6 import org.springframework.format.annotation.DateTimeFormat;
8 7 import java.time.LocalDateTime;
9 8 import cn.idev.excel.annotation.*;
... ... @@ -57,4 +56,4 @@ public class InfraStudentRespVO {
57 56 @ExcelProperty("创建时间")
58 57 private LocalDateTime createTime;
59 58  
60 59 -}
  60 +}
61 61 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentSaveReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentSaveReqVO
... ... @@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import javax.validation.constraints.*;
7   -import java.util.*;
  6 +import jakarta.validation.constraints.*;
8 7 import org.springframework.format.annotation.DateTimeFormat;
9 8 import java.time.LocalDateTime;
10 9 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentService renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentService
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
3 3 import java.util.*;
4   -import javax.validation.*;
  4 +import jakarta.validation.*;
5 5 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
6 6 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
7 7 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
... ... @@ -39,6 +39,13 @@ public interface InfraStudentService {
39 39 void deleteStudent(Long id);
40 40  
41 41 /**
  42 + * 批量删除学生
  43 + *
  44 + * @param ids 编号
  45 + */
  46 + void deleteStudentListByIds(List<Long> ids);
  47 +
  48 + /**
42 49 * 获得学生
43 50 *
44 51 * @param id 编号
... ... @@ -87,6 +94,13 @@ public interface InfraStudentService {
87 94 */
88 95 void deleteStudentContact(Long id);
89 96  
  97 + /**
  98 + * 批量删除学生联系人
  99 + *
  100 + * @param ids 编号
  101 + */
  102 + void deleteStudentContactListByIds(List<Long> ids);
  103 +
90 104 /**
91 105 * 获得学生联系人
92 106 *
... ... @@ -128,6 +142,13 @@ public interface InfraStudentService {
128 142 */
129 143 void deleteStudentTeacher(Long id);
130 144  
  145 + /**
  146 + * 批量删除学生班主任
  147 + *
  148 + * @param ids 编号
  149 + */
  150 + void deleteStudentTeacherListByIds(List<Long> ids);
  151 +
131 152 /**
132 153 * 获得学生班主任
133 154 *
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImpl renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentServiceImpl
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import org.springframework.stereotype.Service;
4   -import javax.annotation.Resource;
  5 +import jakarta.annotation.Resource;
5 6 import org.springframework.validation.annotation.Validated;
6 7 import org.springframework.transaction.annotation.Transactional;
7 8  
... ... @@ -19,6 +20,8 @@ import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper;
19 20 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper;
20 21  
21 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  23 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
22 25 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
23 26  
24 27 /**
... ... @@ -42,6 +45,7 @@ public class InfraStudentServiceImpl implements InfraStudentService {
42 45 // 插入
43 46 InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
44 47 studentMapper.insert(student);
  48 +
45 49 // 返回
46 50 return student.getId();
47 51 }
... ... @@ -68,6 +72,18 @@ public class InfraStudentServiceImpl implements InfraStudentService {
68 72 deleteStudentTeacherByStudentId(id);
69 73 }
70 74  
  75 + @Override
  76 + @Transactional(rollbackFor = Exception.class)
  77 + public void deleteStudentListByIds(List<Long> ids) {
  78 + // 删除
  79 + studentMapper.deleteByIds(ids);
  80 +
  81 + // 删除子表
  82 + deleteStudentContactByStudentIds(ids);
  83 + deleteStudentTeacherByStudentIds(ids);
  84 + }
  85 +
  86 +
71 87 private void validateStudentExists(Long id) {
72 88 if (studentMapper.selectById(id) == null) {
73 89 throw exception(STUDENT_NOT_EXISTS);
... ... @@ -93,6 +109,7 @@ public class InfraStudentServiceImpl implements InfraStudentService {
93 109  
94 110 @Override
95 111 public Long createStudentContact(InfraStudentContactDO studentContact) {
  112 + studentContact.clean(); // 清理掉创建、更新时间等相关属性值
96 113 studentContactMapper.insert(studentContact);
97 114 return studentContact.getId();
98 115 }
... ... @@ -102,17 +119,22 @@ public class InfraStudentServiceImpl implements InfraStudentService {
102 119 // 校验存在
103 120 validateStudentContactExists(studentContact.getId());
104 121 // 更新
  122 + studentContact.clean(); // 解决更新情况下:updateTime 不更新
105 123 studentContactMapper.updateById(studentContact);
106 124 }
107 125  
108 126 @Override
109 127 public void deleteStudentContact(Long id) {
110   - // 校验存在
111   - validateStudentContactExists(id);
112 128 // 删除
113 129 studentContactMapper.deleteById(id);
114 130 }
115 131  
  132 + @Override
  133 + public void deleteStudentContactListByIds(List<Long> ids) {
  134 + // 删除
  135 + studentContactMapper.deleteByIds(ids);
  136 + }
  137 +
116 138 @Override
117 139 public InfraStudentContactDO getStudentContact(Long id) {
118 140 return studentContactMapper.selectById(id);
... ... @@ -128,6 +150,10 @@ public class InfraStudentServiceImpl implements InfraStudentService {
128 150 studentContactMapper.deleteByStudentId(studentId);
129 151 }
130 152  
  153 + private void deleteStudentContactByStudentIds(List<Long> studentIds) {
  154 + studentContactMapper.deleteByStudentIds(studentIds);
  155 + }
  156 +
131 157 // ==================== 子表(学生班主任) ====================
132 158  
133 159 @Override
... ... @@ -142,6 +168,7 @@ public class InfraStudentServiceImpl implements InfraStudentService {
142 168 throw exception(STUDENT_TEACHER_EXISTS);
143 169 }
144 170 // 插入
  171 + studentTeacher.clean(); // 清理掉创建、更新时间等相关属性值
145 172 studentTeacherMapper.insert(studentTeacher);
146 173 return studentTeacher.getId();
147 174 }
... ... @@ -151,17 +178,22 @@ public class InfraStudentServiceImpl implements InfraStudentService {
151 178 // 校验存在
152 179 validateStudentTeacherExists(studentTeacher.getId());
153 180 // 更新
  181 + studentTeacher.clean(); // 解决更新情况下:updateTime 不更新
154 182 studentTeacherMapper.updateById(studentTeacher);
155 183 }
156 184  
157 185 @Override
158 186 public void deleteStudentTeacher(Long id) {
159   - // 校验存在
160   - validateStudentTeacherExists(id);
161 187 // 删除
162 188 studentTeacherMapper.deleteById(id);
163 189 }
164 190  
  191 + @Override
  192 + public void deleteStudentTeacherListByIds(List<Long> ids) {
  193 + // 删除
  194 + studentTeacherMapper.deleteByIds(ids);
  195 + }
  196 +
165 197 @Override
166 198 public InfraStudentTeacherDO getStudentTeacher(Long id) {
167 199 return studentTeacherMapper.selectById(id);
... ... @@ -177,4 +209,8 @@ public class InfraStudentServiceImpl implements InfraStudentService {
177 209 studentTeacherMapper.deleteByStudentId(studentId);
178 210 }
179 211  
  212 + private void deleteStudentTeacherByStudentIds(List<Long> studentIds) {
  213 + studentTeacherMapper.deleteByStudentIds(studentIds);
  214 + }
  215 +
180 216 }
181 217 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImplTest renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentServiceImplTest
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.infra.service.demo;
3 3 import org.junit.jupiter.api.Disabled;
4 4 import org.junit.jupiter.api.Test;
5 5  
6   -import javax.annotation.Resource;
  6 +import jakarta.annotation.Resource;
7 7  
8 8 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
9 9  
... ... @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
12 12 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
13 13 import cn.iocoder.yudao.framework.common.pojo.PageResult;
14 14  
15   -import javax.annotation.Resource;
  15 +import jakarta.annotation.Resource;
16 16 import org.springframework.context.annotation.Import;
17 17 import java.util.*;
18 18 import java.time.LocalDateTime;
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentTeacherDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentTeacherDO
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentTeacherMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/java/InfraStudentTeacherMapper
... ... @@ -22,9 +22,16 @@ public interface InfraStudentTeacherMapper extends BaseMapperX&lt;InfraStudentTeach
22 22 .eq(InfraStudentTeacherDO::getStudentId, studentId)
23 23 .orderByDesc(InfraStudentTeacherDO::getId));
24 24 }
  25 + default InfraStudentTeacherDO selectByStudentId(Long studentId) {
  26 + return selectOne(InfraStudentTeacherDO::getStudentId, studentId);
  27 + }
25 28  
26 29 default int deleteByStudentId(Long studentId) {
27 30 return delete(InfraStudentTeacherDO::getStudentId, studentId);
28 31 }
29 32  
  33 + default int deleteByStudentIds(List<Long> studentIds) {
  34 + return deleteBatch(InfraStudentTeacherDO::getStudentId, studentIds);
  35 + }
  36 +
30 37 }
31 38 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/sql/h2 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/sql/h2
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/sql/sql renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/sql/sql
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   --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
13   -SELECT @parentId := LAST_INSERT_ID();
14   -
15   --- 按钮 SQL
16   -INSERT INTO system_menu(
17   - name, permission, type, sort, parent_id,
18   - path, icon, component, status
19   -)
20   -VALUES (
21   - '学生查询', 'infra:student:query', 3, 1, @parentId,
22   - '', '', '', 0
23   -);
24   -INSERT INTO system_menu(
25   - name, permission, type, sort, parent_id,
26   - path, icon, component, status
27   -)
28   -VALUES (
29   - '学生创建', 'infra:student:create', 3, 2, @parentId,
30   - '', '', '', 0
31   -);
32   -INSERT INTO system_menu(
33   - name, permission, type, sort, parent_id,
34   - path, icon, component, status
35   -)
36   -VALUES (
37   - '学生更新', 'infra:student:update', 3, 3, @parentId,
38   - '', '', '', 0
39   -);
40   -INSERT INTO system_menu(
41   - name, permission, type, sort, parent_id,
42   - path, icon, component, status
43   -)
44   -VALUES (
45   - '学生删除', 'infra:student:delete', 3, 4, @parentId,
46   - '', '', '', 0
47   -);
48   -INSERT INTO system_menu(
49   - name, permission, type, sort, parent_id,
50   - path, icon, component, status
51   -)
52   -VALUES (
53   - '学生导出', 'infra:student:export', 3, 5, @parentId,
54   - '', '', '', 0
55   -);
56 1 \ No newline at end of file
  2 +-- 菜单 SQL
  3 +INSERT INTO system_menu(
  4 + name, permission, type, sort, parent_id,
  5 + path, icon, component, status, component_name
  6 +)
  7 +VALUES (
  8 + '学生管理', '', 2, 0, 888,
  9 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  10 +);
  11 +
  12 +-- 按钮父菜单ID
  13 +SELECT @parentId := LAST_INSERT_ID();
  14 +
  15 +-- 按钮 SQL
  16 +INSERT INTO system_menu(
  17 + name, permission, type, sort, parent_id,
  18 + path, icon, component, status
  19 +)
  20 +VALUES (
  21 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  22 + '', '', '', 0
  23 +);
  24 +INSERT INTO system_menu(
  25 + name, permission, type, sort, parent_id,
  26 + path, icon, component, status
  27 +)
  28 +VALUES (
  29 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  30 + '', '', '', 0
  31 +);
  32 +INSERT INTO system_menu(
  33 + name, permission, type, sort, parent_id,
  34 + path, icon, component, status
  35 +)
  36 +VALUES (
  37 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  38 + '', '', '', 0
  39 +);
  40 +INSERT INTO system_menu(
  41 + name, permission, type, sort, parent_id,
  42 + path, icon, component, status
  43 +)
  44 +VALUES (
  45 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  46 + '', '', '', 0
  47 +);
  48 +INSERT INTO system_menu(
  49 + name, permission, type, sort, parent_id,
  50 + path, icon, component, status
  51 +)
  52 +VALUES (
  53 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  54 + '', '', '', 0
  55 +);
57 56 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/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 StudentContact {
  9 + id: number; // 编号
  10 + studentId?: number; // 学生编号
  11 + name?: string; // 名字
  12 + description?: string; // 简介
  13 + birthday?: string | Dayjs; // 出生日期
  14 + sex?: number; // 性别
  15 + enabled?: boolean; // 是否有效
  16 + avatar?: string; // 头像
  17 + video: string; // 附件
  18 + memo?: string; // 备注
  19 + }
  20 +
  21 + /** 学生班主任信息 */
  22 + export interface StudentTeacher {
  23 + id: number; // 编号
  24 + studentId?: number; // 学生编号
  25 + name?: string; // 名字
  26 + description?: string; // 简介
  27 + birthday?: string | Dayjs; // 出生日期
  28 + sex?: number; // 性别
  29 + enabled?: boolean; // 是否有效
  30 + avatar?: string; // 头像
  31 + video: string; // 附件
  32 + memo?: string; // 备注
  33 + }
  34 +
  35 + /** 学生信息 */
  36 + export interface Student {
  37 + id: number; // 编号
  38 + name?: string; // 名字
  39 + description?: string; // 简介
  40 + birthday?: string | Dayjs; // 出生日期
  41 + sex?: number; // 性别
  42 + enabled?: boolean; // 是否有效
  43 + avatar?: string; // 头像
  44 + video?: string; // 附件
  45 + memo?: string; // 备注
  46 + }
  47 +}
  48 +
  49 +/** 查询学生分页 */
  50 +export function getStudentPage(params: PageParam) {
  51 + return requestClient.get<PageResult<StudentApi.Student>>('/infra/student/page', { params });
  52 +}
  53 +
  54 +/** 查询学生详情 */
  55 +export function getStudent(id: number) {
  56 + return requestClient.get<StudentApi.Student>(`/infra/student/get?id=${id}`);
  57 +}
  58 +
  59 +/** 新增学生 */
  60 +export function createStudent(data: StudentApi.Student) {
  61 + return requestClient.post('/infra/student/create', data);
  62 +}
  63 +
  64 +/** 修改学生 */
  65 +export function updateStudent(data: StudentApi.Student) {
  66 + return requestClient.put('/infra/student/update', data);
  67 +}
  68 +
  69 +/** 删除学生 */
  70 +export function deleteStudent(id: number) {
  71 + return requestClient.delete(`/infra/student/delete?id=${id}`);
  72 +}
  73 +
  74 +/** 批量删除学生 */
  75 +export function deleteStudentList(ids: number[]) {
  76 + return requestClient.delete(`/infra/student/delete-list?ids=${ids.join(',')}`)
  77 +}
  78 +
  79 +/** 导出学生 */
  80 +export function exportStudent(params: any) {
  81 + return requestClient.download('/infra/student/export-excel', { params });
  82 +}
  83 +
  84 +
  85 +// ==================== 子表(学生联系人) ====================
  86 +
  87 +/** 获得学生联系人分页 */
  88 +export function getStudentContactPage(params: PageParam) {
  89 + return requestClient.get<PageResult<StudentApi.StudentContact>>(`/infra/student/student-contact/page`, { params });
  90 +}
  91 + /** 新增学生联系人 */
  92 +export function createStudentContact(data: StudentApi.StudentContact) {
  93 + return requestClient.post(`/infra/student/student-contact/create`, data);
  94 +}
  95 +
  96 +/** 修改学生联系人 */
  97 +export function updateStudentContact(data: StudentApi.StudentContact) {
  98 + return requestClient.put(`/infra/student/student-contact/update`, data);
  99 +}
  100 +
  101 +/** 删除学生联系人 */
  102 +export function deleteStudentContact(id: number) {
  103 + return requestClient.delete(`/infra/student/student-contact/delete?id=${id}`);
  104 +}
  105 +
  106 +/** 批量删除学生联系人 */
  107 +export function deleteStudentContactList(ids: number[]) {
  108 + return requestClient.delete(`/infra/student/student-contact/delete-list?ids=${ids.join(',')}`)
  109 +}
  110 +
  111 +/** 获得学生联系人 */
  112 +export function getStudentContact(id: number) {
  113 + return requestClient.get<StudentApi.StudentContact>(`/infra/student/student-contact/get?id=${id}`);
  114 +}
  115 +
  116 +// ==================== 子表(学生班主任) ====================
  117 +
  118 +/** 获得学生班主任分页 */
  119 +export function getStudentTeacherPage(params: PageParam) {
  120 + return requestClient.get<PageResult<StudentApi.StudentTeacher>>(`/infra/student/student-teacher/page`, { params });
  121 +}
  122 + /** 新增学生班主任 */
  123 +export function createStudentTeacher(data: StudentApi.StudentTeacher) {
  124 + return requestClient.post(`/infra/student/student-teacher/create`, data);
  125 +}
  126 +
  127 +/** 修改学生班主任 */
  128 +export function updateStudentTeacher(data: StudentApi.StudentTeacher) {
  129 + return requestClient.put(`/infra/student/student-teacher/update`, data);
  130 +}
  131 +
  132 +/** 删除学生班主任 */
  133 +export function deleteStudentTeacher(id: number) {
  134 + return requestClient.delete(`/infra/student/student-teacher/delete?id=${id}`);
  135 +}
  136 +
  137 +/** 批量删除学生班主任 */
  138 +export function deleteStudentTeacherList(ids: number[]) {
  139 + return requestClient.delete(`/infra/student/student-teacher/delete-list?ids=${ids.join(',')}`)
  140 +}
  141 +
  142 +/** 获得学生班主任 */
  143 +export function getStudentTeacher(id: number) {
  144 + return requestClient.get<StudentApi.StudentTeacher>(`/infra/student/student-teacher/get?id=${id}`);
  145 +}
0 146 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/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_master_erp/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 + import StudentContactList from './modules/student-contact-list.vue'
  19 + import StudentTeacherList from './modules/student-teacher-list.vue'
  20 +
  21 +import { $t } from '#/locales';
  22 +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/demo';
  23 +
  24 + /** 子表的列表 */
  25 +const subTabsName = ref('studentContact')
  26 +const selectStudent = ref<StudentApi.Student>();
  27 +async function onCellClick({ row }: { row: StudentApi.Student }) {
  28 + selectStudent.value = row
  29 +}
  30 +
  31 +const loading = ref(true) // 列表的加载中
  32 +const list = ref<StudentApi.Student[]>([]) // 列表的数据
  33 +
  34 +const total = ref(0) // 列表的总页数
  35 +const queryParams = reactive({
  36 + pageNo: 1,
  37 + pageSize: 10,
  38 + name: undefined,
  39 + birthday: undefined,
  40 + birthday: undefined,
  41 + sex: undefined,
  42 + enabled: undefined,
  43 + createTime: undefined,
  44 +})
  45 +const queryFormRef = ref() // 搜索的表单
  46 +const exportLoading = ref(false) // 导出的加载中
  47 +
  48 +/** 查询列表 */
  49 +async function getList() {
  50 + loading.value = true
  51 + try {
  52 + const params = cloneDeep(queryParams) as any;
  53 + if (params.birthday && Array.isArray(params.birthday)) {
  54 + params.birthday = (params.birthday as string[]).join(',');
  55 + }
  56 + if (params.createTime && Array.isArray(params.createTime)) {
  57 + params.createTime = (params.createTime as string[]).join(',');
  58 + }
  59 + const data = await getStudentPage(params)
  60 + list.value = data.list
  61 + total.value = data.total
  62 + } finally {
  63 + loading.value = false
  64 + }
  65 +}
  66 +
  67 +/** 搜索按钮操作 */
  68 +function handleQuery() {
  69 + queryParams.pageNo = 1
  70 + getList()
  71 +}
  72 +
  73 +/** 重置按钮操作 */
  74 +function resetQuery() {
  75 + queryFormRef.value.resetFields()
  76 + handleQuery()
  77 +}
  78 +
  79 +const [FormModal, formModalApi] = useVbenModal({
  80 + connectedComponent: StudentForm,
  81 + destroyOnClose: true,
  82 +});
  83 +
  84 +/** 创建学生 */
  85 +function handleCreate() {
  86 + formModalApi.setData(null).open();
  87 +}
  88 +
  89 +/** 编辑学生 */
  90 +function handleEdit(row: StudentApi.Student) {
  91 + formModalApi.setData(row).open();
  92 +}
  93 +
  94 +
  95 +/** 删除学生 */
  96 +async function handleDelete(row: StudentApi.Student) {
  97 + const hideLoading = message.loading({
  98 + content: $t('ui.actionMessage.deleting', [row.id]),
  99 + duration: 0,
  100 + });
  101 + try {
  102 + await deleteStudent(row.id!);
  103 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  104 + await getList();
  105 + } finally {
  106 + hideLoading();
  107 + }
  108 +}
  109 +
  110 +/** 批量删除学生 */
  111 +async function handleDeleteBatch() {
  112 + const hideLoading = message.loading({
  113 + content: $t('ui.actionMessage.deleting'),
  114 + duration: 0,
  115 + });
  116 + try {
  117 + await deleteStudentList(checkedIds.value);
  118 + checkedIds.value = [];
  119 + message.success($t('ui.actionMessage.deleteSuccess'));
  120 + await getList();
  121 + } finally {
  122 + hideLoading();
  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 +
  159 + <Card v-if="!hiddenSearchBar" class="mb-4">
  160 + <!-- 搜索工作栏 -->
  161 + <Form
  162 + :model="queryParams"
  163 + ref="queryFormRef"
  164 + layout="inline"
  165 + >
  166 + <Form.Item label="名字" name="name">
  167 + <Input
  168 + v-model:value="queryParams.name"
  169 + placeholder="请输入名字"
  170 + allowClear
  171 + @pressEnter="handleQuery"
  172 + class="w-full"
  173 + />
  174 + </Form.Item>
  175 + <Form.Item label="出生日期" name="birthday">
  176 + <DatePicker
  177 + v-model:value="queryParams.birthday"
  178 + valueFormat="YYYY-MM-DD"
  179 + placeholder="选择出生日期"
  180 + allowClear
  181 + class="w-full"
  182 + />
  183 + </Form.Item>
  184 + <Form.Item label="性别" name="sex">
  185 + <Select
  186 + v-model:value="queryParams.sex"
  187 + placeholder="请选择性别"
  188 + allowClear
  189 + class="w-full"
  190 + >
  191 + <Select.Option
  192 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  193 + :key="dict.value"
  194 + :value="dict.value"
  195 + >
  196 + {{ dict.label }}
  197 + </Select.Option>
  198 + </Select>
  199 + </Form.Item>
  200 + <Form.Item label="是否有效" name="enabled">
  201 + <Select
  202 + v-model:value="queryParams.enabled"
  203 + placeholder="请选择是否有效"
  204 + allowClear
  205 + class="w-full"
  206 + >
  207 + <Select.Option
  208 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  209 + :key="dict.value"
  210 + :value="dict.value"
  211 + >
  212 + {{ dict.label }}
  213 + </Select.Option>
  214 + </Select>
  215 + </Form.Item>
  216 + <Form.Item label="创建时间" name="createTime">
  217 + <RangePicker
  218 + v-model:value="queryParams.createTime"
  219 + v-bind="getRangePickerDefaultProps()"
  220 + class="w-full"
  221 + />
  222 + </Form.Item>
  223 + <Form.Item>
  224 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  225 + <Button class="ml-2" @click="handleQuery" type="primary">
  226 + 搜索
  227 + </Button>
  228 + </Form.Item>
  229 + </Form>
  230 + </Card>
  231 +
  232 + <!-- 列表 -->
  233 + <Card title="学生">
  234 + <template #extra>
  235 + <VbenVxeTableToolbar
  236 + ref="tableToolbarRef"
  237 + v-model:hidden-search="hiddenSearchBar"
  238 + >
  239 + <Button
  240 + class="ml-2"
  241 + :icon="h(Plus)"
  242 + type="primary"
  243 + @click="handleCreate"
  244 + v-access:code="['infra:student:create']"
  245 + >
  246 + {{ $t('ui.actionTitle.create', ['学生']) }}
  247 + </Button>
  248 + <Button
  249 + :icon="h(Download)"
  250 + type="primary"
  251 + class="ml-2"
  252 + :loading="exportLoading"
  253 + @click="handleExport"
  254 + v-access:code="['infra:student:export']"
  255 + >
  256 + {{ $t('ui.actionTitle.export') }}
  257 + </Button>
  258 + <Button
  259 + :icon="h(Trash2)"
  260 + type="primary"
  261 + danger
  262 + class="ml-2"
  263 + :disabled="isEmpty(checkedIds)"
  264 + @click="handleDeleteBatch"
  265 + v-access:code="['infra:student:delete']"
  266 + >
  267 + 批量删除
  268 + </Button>
  269 + </VbenVxeTableToolbar>
  270 + </template>
  271 + <VxeTable
  272 + ref="tableRef"
  273 + :data="list"
  274 + @cell-click="onCellClick"
  275 + :row-config="{
  276 + keyField: 'id',
  277 + isHover: true,
  278 + isCurrent: true,
  279 + }"
  280 + show-overflow
  281 + :loading="loading"
  282 + @checkboxAll="handleRowCheckboxChange"
  283 + @checkboxChange="handleRowCheckboxChange"
  284 + >
  285 + <VxeColumn type="checkbox" width="40" />
  286 + <VxeColumn field="id" title="编号" align="center" />
  287 + <VxeColumn field="name" title="名字" align="center" />
  288 + <VxeColumn field="description" title="简介" align="center" />
  289 + <VxeColumn field="birthday" title="出生日期" align="center">
  290 + <template #default="{row}">
  291 + {{formatDateTime(row.birthday)}}
  292 + </template>
  293 + </VxeColumn>
  294 + <VxeColumn field="sex" title="性别" align="center">
  295 + <template #default="{row}">
  296 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  297 + </template>
  298 + </VxeColumn>
  299 + <VxeColumn field="enabled" title="是否有效" align="center">
  300 + <template #default="{row}">
  301 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  302 + </template>
  303 + </VxeColumn>
  304 + <VxeColumn field="avatar" title="头像" align="center" />
  305 + <VxeColumn field="video" title="附件" align="center" />
  306 + <VxeColumn field="memo" title="备注" align="center" />
  307 + <VxeColumn field="createTime" title="创建时间" align="center">
  308 + <template #default="{row}">
  309 + {{formatDateTime(row.createTime)}}
  310 + </template>
  311 + </VxeColumn>
  312 + <VxeColumn field="operation" title="操作" align="center">
  313 + <template #default="{row}">
  314 + <Button
  315 + size="small"
  316 + type="link"
  317 + @click="handleEdit(row)"
  318 + v-access:code="['infra:student:update']"
  319 + >
  320 + {{ $t('ui.actionTitle.edit') }}
  321 + </Button>
  322 + <Button
  323 + size="small"
  324 + type="link"
  325 + danger
  326 + class="ml-2"
  327 + @click="handleDelete(row)"
  328 + v-access:code="['infra:student:delete']"
  329 + >
  330 + {{ $t('ui.actionTitle.delete') }}
  331 + </Button>
  332 + </template>
  333 + </VxeColumn>
  334 + </VxeTable>
  335 + <!-- 分页 -->
  336 + <div class="mt-2 flex justify-end">
  337 + <Pagination
  338 + :total="total"
  339 + v-model:current="queryParams.pageNo"
  340 + v-model:page-size="queryParams.pageSize"
  341 + show-size-changer
  342 + @change="getList"
  343 + />
  344 + </div>
  345 + </Card>
  346 + <Card>
  347 + <!-- 子表的表单 -->
  348 + <Tabs v-model:active-key="subTabsName">
  349 + <Tabs.TabPane key="studentContact" tab="学生联系人" force-render>
  350 + <StudentContactList :student-id="selectStudent?.id" />
  351 + </Tabs.TabPane>
  352 + <Tabs.TabPane key="studentTeacher" tab="学生班主任" force-render>
  353 + <StudentTeacherList :student-id="selectStudent?.id" />
  354 + </Tabs.TabPane>
  355 + </Tabs>
  356 + </Card>
  357 + </Page>
  358 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/vue/student-contact-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 +
  16 +import { getStudentContact, createStudentContact, updateStudentContact } from '#/api/infra/demo';
  17 +
  18 +const emit = defineEmits(['success']);
  19 +const getTitle = computed(() => {
  20 + return formData.value?.id
  21 + ? $t('ui.actionTitle.edit', ['学生联系人'])
  22 + : $t('ui.actionTitle.create', ['学生联系人']);
  23 +});
  24 +
  25 +const formRef = ref();
  26 +const formData = ref<Partial<StudentApi.StudentContact>>({
  27 + id: undefined,
  28 + studentId: undefined,
  29 + name: undefined,
  30 + description: undefined,
  31 + birthday: undefined,
  32 + sex: undefined,
  33 + enabled: undefined,
  34 + avatar: undefined,
  35 + video: undefined,
  36 + memo: undefined,
  37 +});
  38 +const rules: Record<string, Rule[]> = {
  39 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  40 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  41 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  42 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  43 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  44 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  45 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  46 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  47 +};
  48 +
  49 +const [Modal, modalApi] = useVbenModal({
  50 + async onConfirm() {
  51 + await formRef.value?.validate();
  52 +
  53 + modalApi.lock();
  54 + // 提交表单
  55 + const data = formData.value as StudentApi.StudentContact;
  56 + try {
  57 + await (formData.value?.id ? updateStudentContact(data) : createStudentContact(data));
  58 + // 关闭并提示
  59 + await modalApi.close();
  60 + emit('success');
  61 + message.success({
  62 + content: $t('ui.actionMessage.operationSuccess'),
  63 + });
  64 + } finally {
  65 + modalApi.unlock();
  66 + }
  67 + },
  68 + async onOpenChange(isOpen: boolean) {
  69 + if (!isOpen) {
  70 + resetForm()
  71 + return;
  72 + }
  73 +
  74 + // 加载数据
  75 + let data = modalApi.getData<StudentApi.StudentContact>();
  76 + if (!data) {
  77 + return;
  78 + }
  79 + if (data.id) {
  80 + modalApi.lock();
  81 + try {
  82 + data = await getStudentContact(data.id);
  83 + } finally {
  84 + modalApi.unlock();
  85 + }
  86 + }
  87 + // 设置到 values
  88 + formData.value = data;
  89 + },
  90 +});
  91 +
  92 +/** 重置表单 */
  93 +function resetForm(){
  94 + formData.value = {
  95 + id: undefined,
  96 + studentId: undefined,
  97 + name: undefined,
  98 + description: undefined,
  99 + birthday: undefined,
  100 + sex: undefined,
  101 + enabled: undefined,
  102 + avatar: undefined,
  103 + video: undefined,
  104 + memo: undefined,
  105 + };
  106 + formRef.value?.resetFields();
  107 +}
  108 +</script>
  109 +
  110 +<template>
  111 + <Modal :title="getTitle">
  112 + <Form
  113 + ref="formRef"
  114 + :model="formData"
  115 + :rules="rules"
  116 + :label-col="{ span: 5 }"
  117 + :wrapper-col="{ span: 18 }"
  118 + >
  119 + <Form.Item label="名字" name="name">
  120 + <Input v-model:value="formData.name" placeholder="请输入名字" />
  121 + </Form.Item>
  122 + <Form.Item label="简介" name="description">
  123 + <Textarea v-model:value="formData.description" placeholder="请输入简介" />
  124 + </Form.Item>
  125 + <Form.Item label="出生日期" name="birthday">
  126 + <DatePicker
  127 + v-model:value="formData.birthday"
  128 + valueFormat="x"
  129 + placeholder="选择出生日期"
  130 + />
  131 + </Form.Item>
  132 + <Form.Item label="性别" name="sex">
  133 + <Select v-model:value="formData.sex" placeholder="请选择性别">
  134 + <Select.Option
  135 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  136 + :key="dict.value"
  137 + :value="dict.value"
  138 + >
  139 + {{ dict.label }}
  140 + </Select.Option>
  141 + </Select>
  142 + </Form.Item>
  143 + <Form.Item label="是否有效" name="enabled">
  144 + <RadioGroup v-model:value="formData.enabled">
  145 + <Radio
  146 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  147 + :key="dict.value"
  148 + :value="dict.value"
  149 + >
  150 + {{ dict.label }}
  151 + </Radio>
  152 + </RadioGroup>
  153 + </Form.Item>
  154 + <Form.Item label="头像" name="avatar">
  155 + <ImageUpload v-model:value="formData.avatar" />
  156 + </Form.Item>
  157 + <Form.Item label="附件" name="video">
  158 + <FileUpload v-model:value="formData.video" />
  159 + </Form.Item>
  160 + <Form.Item label="备注" name="memo">
  161 + <RichTextarea v-model="formData.memo" height="500px" />
  162 + </Form.Item>
  163 + </Form>
  164 + </Modal>
  165 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/vue/student-contact-list 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +import type { VxeTableInstance } from '#/adapter/vxe-table';
  4 +
  5 +import { reactive, ref, h, nextTick, watch, onMounted } from 'vue';
  6 +
  7 +import { DICT_TYPE } from '@vben/constants';
  8 +import { getDictOptions } from '@vben/hooks';
  9 +
  10 +import { DictTag } from '#/components/dict-tag';
  11 +import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
  12 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  13 +import { formatDateTime } from '@vben/utils';
  14 +
  15 + import { useVbenModal } from '@vben/common-ui';
  16 +import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table';
  17 +import StudentContactForm from './student-contact-form.vue'
  18 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  19 +import { ImageUpload, FileUpload } from "#/components/upload";
  20 +import { message, Button, Card, Tabs, Pagination, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, RangePicker, DatePicker, TreeSelect } from 'ant-design-vue';
  21 +import { Plus, Trash2 } from '@vben/icons';
  22 +import { $t } from '#/locales';
  23 +
  24 + import { deleteStudentContact, deleteStudentContactList, getStudentContactPage } from '#/api/infra/demo';
  25 +import { isEmpty, cloneDeep } from '@vben/utils';
  26 +
  27 +const props = defineProps<{
  28 + studentId?: number // 学生编号(主表的关联字段)
  29 +}>()
  30 +
  31 + const [FormModal, formModalApi] = useVbenModal({
  32 + connectedComponent: StudentContactForm,
  33 + destroyOnClose: true,
  34 +});
  35 +
  36 +/** 创建学生联系人 */
  37 +function handleCreate() {
  38 + if (!props.studentId){
  39 + message.warning("请先选择一个学生!")
  40 + return
  41 + }
  42 + formModalApi.setData({studentId: props.studentId}).open();
  43 +}
  44 +
  45 +/** 编辑学生联系人 */
  46 +function handleEdit(row: StudentApi.StudentContact) {
  47 + formModalApi.setData(row).open();
  48 +}
  49 +
  50 +/** 删除学生联系人 */
  51 +async function handleDelete(row: StudentApi.StudentContact) {
  52 + const hideLoading = message.loading({
  53 + content: $t('ui.actionMessage.deleting', [row.id]),
  54 + duration: 0,
  55 + });
  56 + try {
  57 + await deleteStudentContact(row.id!);
  58 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  59 + await getList();
  60 + } finally {
  61 + hideLoading();
  62 + }
  63 +}
  64 +
  65 +/** 批量删除学生联系人 */
  66 +async function handleDeleteBatch() {
  67 + const hideLoading = message.loading({
  68 + content: $t('ui.actionMessage.deleting'),
  69 + duration: 0,
  70 + });
  71 + try {
  72 + await deleteStudentContactList(checkedIds.value);
  73 + checkedIds.value = [];
  74 + message.success($t('ui.actionMessage.deleteSuccess'));
  75 + await getList();
  76 + } finally {
  77 + hideLoading();
  78 + }
  79 +}
  80 +
  81 +const checkedIds = ref<number[]>([])
  82 +function handleRowCheckboxChange({
  83 + records,
  84 +}: {
  85 + records: StudentApi.StudentContact[];
  86 +}) {
  87 + checkedIds.value = records.map((item) => item.id!);
  88 +}
  89 +
  90 +const loading = ref(true) // 列表的加载中
  91 +const list = ref<StudentApi.StudentContact[]>([]) // 列表的数据
  92 + const total = ref(0) // 列表的总页数
  93 + const queryFormRef = ref() // 搜索的表单
  94 +const queryParams = reactive({
  95 + pageNo: 1,
  96 + pageSize: 10,
  97 + name: undefined,
  98 + birthday: undefined,
  99 + birthday: undefined,
  100 + sex: undefined,
  101 + enabled: undefined,
  102 + createTime: undefined,
  103 +})
  104 +
  105 +/** 搜索按钮操作 */
  106 +function handleQuery() {
  107 + queryParams.pageNo = 1
  108 + getList()
  109 +}
  110 +
  111 +/** 重置按钮操作 */
  112 +function resetQuery() {
  113 + queryFormRef.value.resetFields()
  114 + handleQuery()
  115 +}
  116 + /** 查询列表 */
  117 +async function getList() {
  118 + loading.value = true
  119 + try {
  120 + if (!props.studentId){
  121 + return []
  122 + }
  123 + const params = cloneDeep(queryParams) as any;
  124 + if (params.birthday && Array.isArray(params.birthday)) {
  125 + params.birthday = (params.birthday as string[]).join(',');
  126 + }
  127 + if (params.createTime && Array.isArray(params.createTime)) {
  128 + params.createTime = (params.createTime as string[]).join(',');
  129 + }
  130 + params.studentId = props.studentId;
  131 + const data = await getStudentContactPage(params)
  132 + list.value = data.list
  133 + total.value = data.total
  134 + } finally {
  135 + loading.value = false
  136 + }
  137 +}
  138 +
  139 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  140 +watch(
  141 + () => props.studentId,
  142 + async (val) => {
  143 + if (!val) {
  144 + return;
  145 + }
  146 + await nextTick();
  147 + await getList()
  148 + },
  149 + { immediate: true },
  150 +);
  151 +
  152 + /** 初始化 */
  153 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  154 +onMounted(() => {
  155 + getList();
  156 +});
  157 +</script>
  158 +
  159 +<template>
  160 + <FormModal @success="getList" />
  161 + <div class="h-[600px]">
  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 + :icon="h(Trash2)"
  253 + type="primary"
  254 + danger
  255 + class="ml-2"
  256 + :disabled="isEmpty(checkedIds)"
  257 + @click="handleDeleteBatch"
  258 + v-access:code="['infra:student:delete']"
  259 + >
  260 + 批量删除
  261 + </Button>
  262 + </VbenVxeTableToolbar>
  263 + </template>
  264 + <VxeTable
  265 + ref="tableRef"
  266 + :data="list"
  267 + show-overflow
  268 + :loading="loading"
  269 + @checkboxAll="handleRowCheckboxChange"
  270 + @checkboxChange="handleRowCheckboxChange"
  271 + >
  272 + <VxeColumn type="checkbox" width="40" />
  273 + <VxeColumn field="id" title="编号" align="center" />
  274 + <VxeColumn field="studentId" title="学生编号" align="center" />
  275 + <VxeColumn field="name" title="名字" align="center" />
  276 + <VxeColumn field="description" title="简介" align="center" />
  277 + <VxeColumn field="birthday" title="出生日期" align="center">
  278 + <template #default="{row}">
  279 + {{formatDateTime(row.birthday)}}
  280 + </template>
  281 + </VxeColumn>
  282 + <VxeColumn field="sex" title="性别" align="center">
  283 + <template #default="{row}">
  284 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  285 + </template>
  286 + </VxeColumn>
  287 + <VxeColumn field="enabled" title="是否有效" align="center">
  288 + <template #default="{row}">
  289 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  290 + </template>
  291 + </VxeColumn>
  292 + <VxeColumn field="avatar" title="头像" align="center" />
  293 + <VxeColumn field="video" title="附件" align="center" />
  294 + <VxeColumn field="memo" title="备注" align="center" />
  295 + <VxeColumn field="createTime" title="创建时间" align="center">
  296 + <template #default="{row}">
  297 + {{formatDateTime(row.createTime)}}
  298 + </template>
  299 + </VxeColumn>
  300 + <VxeColumn field="operation" title="操作" align="center">
  301 + <template #default="{row}">
  302 + <Button
  303 + size="small"
  304 + type="link"
  305 + @click="handleEdit(row)"
  306 + v-access:code="['infra:student:update']"
  307 + >
  308 + {{ $t('ui.actionTitle.edit') }}
  309 + </Button>
  310 + <Button
  311 + size="small"
  312 + type="link"
  313 + danger
  314 + class="ml-2"
  315 + @click="handleDelete(row)"
  316 + v-access:code="['infra:student:delete']"
  317 + >
  318 + {{ $t('ui.actionTitle.delete') }}
  319 + </Button>
  320 + </template>
  321 + </VxeColumn>
  322 + </VxeTable>
  323 + <!-- 分页 -->
  324 + <div class="mt-2 flex justify-end">
  325 + <Pagination
  326 + :total="total"
  327 + v-model:current="queryParams.pageNo"
  328 + v-model:page-size="queryParams.pageSize"
  329 + show-size-changer
  330 + @change="getList"
  331 + />
  332 + </div>
  333 + </Card>
  334 + </div>
  335 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/vue/student-teacher-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 +
  16 +import { getStudentTeacher, createStudentTeacher, updateStudentTeacher } from '#/api/infra/demo';
  17 +
  18 +const emit = defineEmits(['success']);
  19 +const getTitle = computed(() => {
  20 + return formData.value?.id
  21 + ? $t('ui.actionTitle.edit', ['学生班主任'])
  22 + : $t('ui.actionTitle.create', ['学生班主任']);
  23 +});
  24 +
  25 +const formRef = ref();
  26 +const formData = ref<Partial<StudentApi.StudentTeacher>>({
  27 + id: undefined,
  28 + studentId: undefined,
  29 + name: undefined,
  30 + description: undefined,
  31 + birthday: undefined,
  32 + sex: undefined,
  33 + enabled: undefined,
  34 + avatar: undefined,
  35 + video: undefined,
  36 + memo: undefined,
  37 +});
  38 +const rules: Record<string, Rule[]> = {
  39 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  40 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  41 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  42 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  43 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  44 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  45 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  46 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  47 +};
  48 +
  49 +const [Modal, modalApi] = useVbenModal({
  50 + async onConfirm() {
  51 + await formRef.value?.validate();
  52 +
  53 + modalApi.lock();
  54 + // 提交表单
  55 + const data = formData.value as StudentApi.StudentTeacher;
  56 + try {
  57 + await (formData.value?.id ? updateStudentTeacher(data) : createStudentTeacher(data));
  58 + // 关闭并提示
  59 + await modalApi.close();
  60 + emit('success');
  61 + message.success({
  62 + content: $t('ui.actionMessage.operationSuccess'),
  63 + });
  64 + } finally {
  65 + modalApi.unlock();
  66 + }
  67 + },
  68 + async onOpenChange(isOpen: boolean) {
  69 + if (!isOpen) {
  70 + resetForm()
  71 + return;
  72 + }
  73 +
  74 + // 加载数据
  75 + let data = modalApi.getData<StudentApi.StudentTeacher>();
  76 + if (!data) {
  77 + return;
  78 + }
  79 + if (data.id) {
  80 + modalApi.lock();
  81 + try {
  82 + data = await getStudentTeacher(data.id);
  83 + } finally {
  84 + modalApi.unlock();
  85 + }
  86 + }
  87 + // 设置到 values
  88 + formData.value = data;
  89 + },
  90 +});
  91 +
  92 +/** 重置表单 */
  93 +function resetForm(){
  94 + formData.value = {
  95 + id: undefined,
  96 + studentId: undefined,
  97 + name: undefined,
  98 + description: undefined,
  99 + birthday: undefined,
  100 + sex: undefined,
  101 + enabled: undefined,
  102 + avatar: undefined,
  103 + video: undefined,
  104 + memo: undefined,
  105 + };
  106 + formRef.value?.resetFields();
  107 +}
  108 +</script>
  109 +
  110 +<template>
  111 + <Modal :title="getTitle">
  112 + <Form
  113 + ref="formRef"
  114 + :model="formData"
  115 + :rules="rules"
  116 + :label-col="{ span: 5 }"
  117 + :wrapper-col="{ span: 18 }"
  118 + >
  119 + <Form.Item label="名字" name="name">
  120 + <Input v-model:value="formData.name" placeholder="请输入名字" />
  121 + </Form.Item>
  122 + <Form.Item label="简介" name="description">
  123 + <Textarea v-model:value="formData.description" placeholder="请输入简介" />
  124 + </Form.Item>
  125 + <Form.Item label="出生日期" name="birthday">
  126 + <DatePicker
  127 + v-model:value="formData.birthday"
  128 + valueFormat="x"
  129 + placeholder="选择出生日期"
  130 + />
  131 + </Form.Item>
  132 + <Form.Item label="性别" name="sex">
  133 + <Select v-model:value="formData.sex" placeholder="请选择性别">
  134 + <Select.Option
  135 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  136 + :key="dict.value"
  137 + :value="dict.value"
  138 + >
  139 + {{ dict.label }}
  140 + </Select.Option>
  141 + </Select>
  142 + </Form.Item>
  143 + <Form.Item label="是否有效" name="enabled">
  144 + <RadioGroup v-model:value="formData.enabled">
  145 + <Radio
  146 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  147 + :key="dict.value"
  148 + :value="dict.value"
  149 + >
  150 + {{ dict.label }}
  151 + </Radio>
  152 + </RadioGroup>
  153 + </Form.Item>
  154 + <Form.Item label="头像" name="avatar">
  155 + <ImageUpload v-model:value="formData.avatar" />
  156 + </Form.Item>
  157 + <Form.Item label="附件" name="video">
  158 + <FileUpload v-model:value="formData.video" />
  159 + </Form.Item>
  160 + <Form.Item label="备注" name="memo">
  161 + <RichTextarea v-model="formData.memo" height="500px" />
  162 + </Form.Item>
  163 + </Form>
  164 + </Modal>
  165 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/vue/student-teacher-list 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +import type { VxeTableInstance } from '#/adapter/vxe-table';
  4 +
  5 +import { reactive, ref, h, nextTick, watch, onMounted } from 'vue';
  6 +
  7 +import { DICT_TYPE } from '@vben/constants';
  8 +import { getDictOptions } from '@vben/hooks';
  9 +
  10 +import { DictTag } from '#/components/dict-tag';
  11 +import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
  12 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  13 +import { formatDateTime } from '@vben/utils';
  14 +
  15 + import { useVbenModal } from '@vben/common-ui';
  16 +import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table';
  17 +import StudentTeacherForm from './student-teacher-form.vue'
  18 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  19 +import { ImageUpload, FileUpload } from "#/components/upload";
  20 +import { message, Button, Card, Tabs, Pagination, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, RangePicker, DatePicker, TreeSelect } from 'ant-design-vue';
  21 +import { Plus, Trash2 } from '@vben/icons';
  22 +import { $t } from '#/locales';
  23 +
  24 + import { deleteStudentTeacher, deleteStudentTeacherList, getStudentTeacherPage } from '#/api/infra/demo';
  25 +import { isEmpty, cloneDeep } from '@vben/utils';
  26 +
  27 +const props = defineProps<{
  28 + studentId?: number // 学生编号(主表的关联字段)
  29 +}>()
  30 +
  31 + const [FormModal, formModalApi] = useVbenModal({
  32 + connectedComponent: StudentTeacherForm,
  33 + destroyOnClose: true,
  34 +});
  35 +
  36 +/** 创建学生班主任 */
  37 +function handleCreate() {
  38 + if (!props.studentId){
  39 + message.warning("请先选择一个学生!")
  40 + return
  41 + }
  42 + formModalApi.setData({studentId: props.studentId}).open();
  43 +}
  44 +
  45 +/** 编辑学生班主任 */
  46 +function handleEdit(row: StudentApi.StudentTeacher) {
  47 + formModalApi.setData(row).open();
  48 +}
  49 +
  50 +/** 删除学生班主任 */
  51 +async function handleDelete(row: StudentApi.StudentTeacher) {
  52 + const hideLoading = message.loading({
  53 + content: $t('ui.actionMessage.deleting', [row.id]),
  54 + duration: 0,
  55 + });
  56 + try {
  57 + await deleteStudentTeacher(row.id!);
  58 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  59 + await getList();
  60 + } finally {
  61 + hideLoading();
  62 + }
  63 +}
  64 +
  65 +/** 批量删除学生班主任 */
  66 +async function handleDeleteBatch() {
  67 + const hideLoading = message.loading({
  68 + content: $t('ui.actionMessage.deleting'),
  69 + duration: 0,
  70 + });
  71 + try {
  72 + await deleteStudentTeacherList(checkedIds.value);
  73 + checkedIds.value = [];
  74 + message.success($t('ui.actionMessage.deleteSuccess'));
  75 + await getList();
  76 + } finally {
  77 + hideLoading();
  78 + }
  79 +}
  80 +
  81 +const checkedIds = ref<number[]>([])
  82 +function handleRowCheckboxChange({
  83 + records,
  84 +}: {
  85 + records: StudentApi.StudentTeacher[];
  86 +}) {
  87 + checkedIds.value = records.map((item) => item.id!);
  88 +}
  89 +
  90 +const loading = ref(true) // 列表的加载中
  91 +const list = ref<StudentApi.StudentTeacher[]>([]) // 列表的数据
  92 + const total = ref(0) // 列表的总页数
  93 + const queryFormRef = ref() // 搜索的表单
  94 +const queryParams = reactive({
  95 + pageNo: 1,
  96 + pageSize: 10,
  97 + name: undefined,
  98 + birthday: undefined,
  99 + birthday: undefined,
  100 + sex: undefined,
  101 + enabled: undefined,
  102 + createTime: undefined,
  103 +})
  104 +
  105 +/** 搜索按钮操作 */
  106 +function handleQuery() {
  107 + queryParams.pageNo = 1
  108 + getList()
  109 +}
  110 +
  111 +/** 重置按钮操作 */
  112 +function resetQuery() {
  113 + queryFormRef.value.resetFields()
  114 + handleQuery()
  115 +}
  116 + /** 查询列表 */
  117 +async function getList() {
  118 + loading.value = true
  119 + try {
  120 + if (!props.studentId){
  121 + return []
  122 + }
  123 + const params = cloneDeep(queryParams) as any;
  124 + if (params.birthday && Array.isArray(params.birthday)) {
  125 + params.birthday = (params.birthday as string[]).join(',');
  126 + }
  127 + if (params.createTime && Array.isArray(params.createTime)) {
  128 + params.createTime = (params.createTime as string[]).join(',');
  129 + }
  130 + params.studentId = props.studentId;
  131 + const data = await getStudentTeacherPage(params)
  132 + list.value = data.list
  133 + total.value = data.total
  134 + } finally {
  135 + loading.value = false
  136 + }
  137 +}
  138 +
  139 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  140 +watch(
  141 + () => props.studentId,
  142 + async (val) => {
  143 + if (!val) {
  144 + return;
  145 + }
  146 + await nextTick();
  147 + await getList()
  148 + },
  149 + { immediate: true },
  150 +);
  151 +
  152 + /** 初始化 */
  153 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  154 +onMounted(() => {
  155 + getList();
  156 +});
  157 +</script>
  158 +
  159 +<template>
  160 + <FormModal @success="getList" />
  161 + <div class="h-[600px]">
  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 + :icon="h(Trash2)"
  253 + type="primary"
  254 + danger
  255 + class="ml-2"
  256 + :disabled="isEmpty(checkedIds)"
  257 + @click="handleDeleteBatch"
  258 + v-access:code="['infra:student:delete']"
  259 + >
  260 + 批量删除
  261 + </Button>
  262 + </VbenVxeTableToolbar>
  263 + </template>
  264 + <VxeTable
  265 + ref="tableRef"
  266 + :data="list"
  267 + show-overflow
  268 + :loading="loading"
  269 + @checkboxAll="handleRowCheckboxChange"
  270 + @checkboxChange="handleRowCheckboxChange"
  271 + >
  272 + <VxeColumn type="checkbox" width="40" />
  273 + <VxeColumn field="id" title="编号" align="center" />
  274 + <VxeColumn field="studentId" title="学生编号" align="center" />
  275 + <VxeColumn field="name" title="名字" align="center" />
  276 + <VxeColumn field="description" title="简介" align="center" />
  277 + <VxeColumn field="birthday" title="出生日期" align="center">
  278 + <template #default="{row}">
  279 + {{formatDateTime(row.birthday)}}
  280 + </template>
  281 + </VxeColumn>
  282 + <VxeColumn field="sex" title="性别" align="center">
  283 + <template #default="{row}">
  284 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  285 + </template>
  286 + </VxeColumn>
  287 + <VxeColumn field="enabled" title="是否有效" align="center">
  288 + <template #default="{row}">
  289 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  290 + </template>
  291 + </VxeColumn>
  292 + <VxeColumn field="avatar" title="头像" align="center" />
  293 + <VxeColumn field="video" title="附件" align="center" />
  294 + <VxeColumn field="memo" title="备注" align="center" />
  295 + <VxeColumn field="createTime" title="创建时间" align="center">
  296 + <template #default="{row}">
  297 + {{formatDateTime(row.createTime)}}
  298 + </template>
  299 + </VxeColumn>
  300 + <VxeColumn field="operation" title="操作" align="center">
  301 + <template #default="{row}">
  302 + <Button
  303 + size="small"
  304 + type="link"
  305 + @click="handleEdit(row)"
  306 + v-access:code="['infra:student:update']"
  307 + >
  308 + {{ $t('ui.actionTitle.edit') }}
  309 + </Button>
  310 + <Button
  311 + size="small"
  312 + type="link"
  313 + danger
  314 + class="ml-2"
  315 + @click="handleDelete(row)"
  316 + v-access:code="['infra:student:delete']"
  317 + >
  318 + {{ $t('ui.actionTitle.delete') }}
  319 + </Button>
  320 + </template>
  321 + </VxeColumn>
  322 + </VxeTable>
  323 + <!-- 分页 -->
  324 + <div class="mt-2 flex justify-end">
  325 + <Pagination
  326 + :total="total"
  327 + v-model:current="queryParams.pageNo"
  328 + v-model:page-size="queryParams.pageSize"
  329 + show-size-changer
  330 + @change="getList"
  331 + />
  332 + </div>
  333 + </Card>
  334 + </div>
  335 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/xml/InfraStudentMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/xml/InfraStudentMapper
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/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/InfraStudentController",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentDO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentContactDO",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentTeacherDO",
  21 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.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" : "java/InfraStudentContactMapper",
  27 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentTeacherMapper",
  30 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java"
  31 +}, {
  32 + "contentPath" : "xml/InfraStudentMapper",
  33 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImpl",
  36 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  37 +}, {
  38 + "contentPath" : "java/InfraStudentService",
  39 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  40 +}, {
  41 + "contentPath" : "java/InfraStudentServiceImplTest",
  42 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  43 +}, {
  44 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  45 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  46 +}, {
  47 + "contentPath" : "sql/sql",
  48 + "filePath" : "sql/sql.sql"
  49 +}, {
  50 + "contentPath" : "sql/h2",
  51 + "filePath" : "sql/h2.sql"
  52 +}, {
  53 + "contentPath" : "vue/index",
  54 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  55 +}, {
  56 + "contentPath" : "vue/form",
  57 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  58 +}, {
  59 + "contentPath" : "ts/index",
  60 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  61 +}, {
  62 + "contentPath" : "vue/student-contact-form",
  63 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-contact-form.vue"
  64 +}, {
  65 + "contentPath" : "vue/student-teacher-form",
  66 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-teacher-form.vue"
  67 +}, {
  68 + "contentPath" : "vue/student-contact-list",
  69 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-contact-list.vue"
  70 +}, {
  71 + "contentPath" : "vue/student-teacher-list",
  72 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-teacher-list.vue"
  73 +} ]
0 74 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/ErrorCodeConstants_手动操作 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/ErrorCodeConstants_手动操作
1   -// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
2   -// ========== 学生 TODO 补充编号 ==========
3   -ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
4 1 \ No newline at end of file
  2 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  3 +// ========== 学生 TODO 补充编号 ==========
  4 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
5 5 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentContactDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentContactDO
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentContactMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentContactMapper
... ... @@ -25,4 +25,8 @@ public interface InfraStudentContactMapper extends BaseMapperX&lt;InfraStudentConta
25 25 return delete(InfraStudentContactDO::getStudentId, studentId);
26 26 }
27 27  
  28 + default int deleteByStudentIds(List<Long> studentIds) {
  29 + return deleteBatch(InfraStudentContactDO::getStudentId, studentIds);
  30 + }
  31 +
28 32 }
29 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentController renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentController
1 1 package cn.iocoder.yudao.module.infra.controller.admin.demo;
2 2  
3 3 import org.springframework.web.bind.annotation.*;
4   -import javax.annotation.Resource;
  4 +import jakarta.annotation.Resource;
5 5 import org.springframework.validation.annotation.Validated;
6 6 import org.springframework.security.access.prepost.PreAuthorize;
7 7 import io.swagger.v3.oas.annotations.tags.Tag;
8 8 import io.swagger.v3.oas.annotations.Parameter;
9 9 import io.swagger.v3.oas.annotations.Operation;
10 10  
11   -import javax.validation.constraints.*;
12   -import javax.validation.*;
13   -import javax.servlet.http.*;
  11 +import jakarta.validation.constraints.*;
  12 +import jakarta.validation.*;
  13 +import jakarta.servlet.http.*;
14 14 import java.util.*;
15 15 import java.io.IOException;
16 16  
... ... @@ -22,8 +22,8 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 22  
23 23 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
24 24  
25   -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
26   -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  25 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  26 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
27 27  
28 28 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
29 29 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
... ... @@ -64,6 +64,15 @@ public class InfraStudentController {
64 64 return success(true);
65 65 }
66 66  
  67 + @DeleteMapping("/delete-list")
  68 + @Parameter(name = "ids", description = "编号", required = true)
  69 + @Operation(summary = "批量删除学生")
  70 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  71 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  72 + studentService.deleteStudentListByIds(ids);
  73 + return success(true);
  74 + }
  75 +
67 76 @GetMapping("/get")
68 77 @Operation(summary = "获得学生")
69 78 @Parameter(name = "id", description = "编号", required = true, example = "1024")
... ... @@ -84,7 +93,7 @@ public class InfraStudentController {
84 93 @GetMapping("/export-excel")
85 94 @Operation(summary = "导出学生 Excel")
86 95 @PreAuthorize("@ss.hasPermission('infra:student:export')")
87   - @OperateLog(type = EXPORT)
  96 + @ApiAccessLog(operateType = EXPORT)
88 97 public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
89 98 HttpServletResponse response) throws IOException {
90 99 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentDO
... ... @@ -64,4 +64,5 @@ public class InfraStudentDO extends BaseDO {
64 64 */
65 65 private String memo;
66 66  
  67 +
67 68 }
68 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentMapper
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentPageReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentPageReqVO
... ... @@ -11,8 +11,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
11 11  
12 12 @Schema(description = "管理后台 - 学生分页 Request VO")
13 13 @Data
14   -@EqualsAndHashCode(callSuper = true)
15   -@ToString(callSuper = true)
16 14 public class InfraStudentPageReqVO extends PageParam {
17 15  
18 16 @Schema(description = "名字", example = "芋头")
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentRespVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentRespVO
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import java.util.*;
7 6 import org.springframework.format.annotation.DateTimeFormat;
8 7 import java.time.LocalDateTime;
9 8 import cn.idev.excel.annotation.*;
... ... @@ -57,4 +56,4 @@ public class InfraStudentRespVO {
57 56 @ExcelProperty("创建时间")
58 57 private LocalDateTime createTime;
59 58  
60 59 -}
  60 +}
61 61 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentSaveReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentSaveReqVO
... ... @@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import javax.validation.constraints.*;
7   -import java.util.*;
  6 +import jakarta.validation.constraints.*;
8 7 import org.springframework.format.annotation.DateTimeFormat;
9 8 import java.time.LocalDateTime;
10 9 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentService renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentService
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
3 3 import java.util.*;
4   -import javax.validation.*;
  4 +import jakarta.validation.*;
5 5 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
6 6 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
7 7 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
... ... @@ -39,6 +39,13 @@ public interface InfraStudentService {
39 39 void deleteStudent(Long id);
40 40  
41 41 /**
  42 + * 批量删除学生
  43 + *
  44 + * @param ids 编号
  45 + */
  46 + void deleteStudentListByIds(List<Long> ids);
  47 +
  48 + /**
42 49 * 获得学生
43 50 *
44 51 * @param id 编号
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImpl renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentServiceImpl
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import org.springframework.stereotype.Service;
4   -import javax.annotation.Resource;
  5 +import jakarta.annotation.Resource;
5 6 import org.springframework.validation.annotation.Validated;
6 7 import org.springframework.transaction.annotation.Transactional;
7 8  
... ... @@ -19,6 +20,8 @@ import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper;
19 20 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper;
20 21  
21 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  23 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
22 25 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
23 26  
24 27 /**
... ... @@ -44,6 +47,7 @@ public class InfraStudentServiceImpl implements InfraStudentService {
44 47 InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
45 48 studentMapper.insert(student);
46 49  
  50 +
47 51 // 插入子表
48 52 createStudentContactList(student.getId(), createReqVO.getStudentContacts());
49 53 createStudentTeacher(student.getId(), createReqVO.getStudentTeacher());
... ... @@ -78,6 +82,18 @@ public class InfraStudentServiceImpl implements InfraStudentService {
78 82 deleteStudentTeacherByStudentId(id);
79 83 }
80 84  
  85 + @Override
  86 + @Transactional(rollbackFor = Exception.class)
  87 + public void deleteStudentListByIds(List<Long> ids) {
  88 + // 删除
  89 + studentMapper.deleteByIds(ids);
  90 +
  91 + // 删除子表
  92 + deleteStudentContactByStudentIds(ids);
  93 + deleteStudentTeacherByStudentIds(ids);
  94 + }
  95 +
  96 +
81 97 private void validateStudentExists(Long id) {
82 98 if (studentMapper.selectById(id) == null) {
83 99 throw exception(STUDENT_NOT_EXISTS);
... ... @@ -102,20 +118,44 @@ public class InfraStudentServiceImpl implements InfraStudentService {
102 118 }
103 119  
104 120 private void createStudentContactList(Long studentId, List<InfraStudentContactDO> list) {
105   - list.forEach(o -> o.setStudentId(studentId));
  121 + if (CollUtil.isEmpty(list)) {
  122 + return;
  123 + }
  124 + list.forEach(o -> o.setStudentId(studentId).clean());
106 125 studentContactMapper.insertBatch(list);
107 126 }
108 127  
109 128 private void updateStudentContactList(Long studentId, List<InfraStudentContactDO> list) {
110   - deleteStudentContactByStudentId(studentId);
111   - list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新
112   - createStudentContactList(studentId, list);
  129 + list.forEach(o -> o.setStudentId(studentId).clean());
  130 + List<InfraStudentContactDO> oldList = studentContactMapper.selectListByStudentId(studentId);
  131 + List<List<InfraStudentContactDO>> diffList = diffList(oldList, list, (oldVal, newVal) -> {
  132 + boolean same = ObjectUtil.equal(oldVal.getId(), newVal.getId());
  133 + if (same) {
  134 + newVal.setId(oldVal.getId()).clean(); // 解决更新情况下:updateTime 不更新
  135 + }
  136 + return same;
  137 + });
  138 +
  139 + // 第二步,批量添加、修改、删除
  140 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  141 + studentContactMapper.insertBatch(diffList.get(0));
  142 + }
  143 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  144 + studentContactMapper.updateBatch(diffList.get(1));
  145 + }
  146 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  147 + studentContactMapper.deleteByIds(convertList(diffList.get(2), InfraStudentContactDO::getId));
  148 + }
113 149 }
114 150  
115 151 private void deleteStudentContactByStudentId(Long studentId) {
116 152 studentContactMapper.deleteByStudentId(studentId);
117 153 }
118 154  
  155 + private void deleteStudentContactByStudentIds(List<Long> studentIds) {
  156 + studentContactMapper.deleteByStudentIds(studentIds);
  157 + }
  158 +
119 159 // ==================== 子表(学生班主任) ====================
120 160  
121 161 @Override
... ... @@ -135,8 +175,7 @@ public class InfraStudentServiceImpl implements InfraStudentService {
135 175 if (studentTeacher == null) {
136 176 return;
137 177 }
138   - studentTeacher.setStudentId(studentId);
139   - studentTeacher.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新
  178 + studentTeacher.setStudentId(studentId).clean();// 解决更新情况下:updateTime 不更新
140 179 studentTeacherMapper.insertOrUpdate(studentTeacher);
141 180 }
142 181  
... ... @@ -144,4 +183,8 @@ public class InfraStudentServiceImpl implements InfraStudentService {
144 183 studentTeacherMapper.deleteByStudentId(studentId);
145 184 }
146 185  
  186 + private void deleteStudentTeacherByStudentIds(List<Long> studentIds) {
  187 + studentTeacherMapper.deleteByStudentIds(studentIds);
  188 + }
  189 +
147 190 }
148 191 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImplTest renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentServiceImplTest
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.infra.service.demo;
3 3 import org.junit.jupiter.api.Disabled;
4 4 import org.junit.jupiter.api.Test;
5 5  
6   -import javax.annotation.Resource;
  6 +import jakarta.annotation.Resource;
7 7  
8 8 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
9 9  
... ... @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
12 12 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
13 13 import cn.iocoder.yudao.framework.common.pojo.PageResult;
14 14  
15   -import javax.annotation.Resource;
  15 +import jakarta.annotation.Resource;
16 16 import org.springframework.context.annotation.Import;
17 17 import java.util.*;
18 18 import java.time.LocalDateTime;
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentTeacherDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentTeacherDO
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentTeacherMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/java/InfraStudentTeacherMapper
... ... @@ -25,4 +25,8 @@ public interface InfraStudentTeacherMapper extends BaseMapperX&lt;InfraStudentTeach
25 25 return delete(InfraStudentTeacherDO::getStudentId, studentId);
26 26 }
27 27  
  28 + default int deleteByStudentIds(List<Long> studentIds) {
  29 + return deleteBatch(InfraStudentTeacherDO::getStudentId, studentIds);
  30 + }
  31 +
28 32 }
29 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/sql/h2 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/sql/h2
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/sql/sql renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/sql/sql
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   --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
13   -SELECT @parentId := LAST_INSERT_ID();
14   -
15   --- 按钮 SQL
16   -INSERT INTO system_menu(
17   - name, permission, type, sort, parent_id,
18   - path, icon, component, status
19   -)
20   -VALUES (
21   - '学生查询', 'infra:student:query', 3, 1, @parentId,
22   - '', '', '', 0
23   -);
24   -INSERT INTO system_menu(
25   - name, permission, type, sort, parent_id,
26   - path, icon, component, status
27   -)
28   -VALUES (
29   - '学生创建', 'infra:student:create', 3, 2, @parentId,
30   - '', '', '', 0
31   -);
32   -INSERT INTO system_menu(
33   - name, permission, type, sort, parent_id,
34   - path, icon, component, status
35   -)
36   -VALUES (
37   - '学生更新', 'infra:student:update', 3, 3, @parentId,
38   - '', '', '', 0
39   -);
40   -INSERT INTO system_menu(
41   - name, permission, type, sort, parent_id,
42   - path, icon, component, status
43   -)
44   -VALUES (
45   - '学生删除', 'infra:student:delete', 3, 4, @parentId,
46   - '', '', '', 0
47   -);
48   -INSERT INTO system_menu(
49   - name, permission, type, sort, parent_id,
50   - path, icon, component, status
51   -)
52   -VALUES (
53   - '学生导出', 'infra:student:export', 3, 5, @parentId,
54   - '', '', '', 0
55   -);
56 1 \ No newline at end of file
  2 +-- 菜单 SQL
  3 +INSERT INTO system_menu(
  4 + name, permission, type, sort, parent_id,
  5 + path, icon, component, status, component_name
  6 +)
  7 +VALUES (
  8 + '学生管理', '', 2, 0, 888,
  9 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  10 +);
  11 +
  12 +-- 按钮父菜单ID
  13 +SELECT @parentId := LAST_INSERT_ID();
  14 +
  15 +-- 按钮 SQL
  16 +INSERT INTO system_menu(
  17 + name, permission, type, sort, parent_id,
  18 + path, icon, component, status
  19 +)
  20 +VALUES (
  21 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  22 + '', '', '', 0
  23 +);
  24 +INSERT INTO system_menu(
  25 + name, permission, type, sort, parent_id,
  26 + path, icon, component, status
  27 +)
  28 +VALUES (
  29 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  30 + '', '', '', 0
  31 +);
  32 +INSERT INTO system_menu(
  33 + name, permission, type, sort, parent_id,
  34 + path, icon, component, status
  35 +)
  36 +VALUES (
  37 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  38 + '', '', '', 0
  39 +);
  40 +INSERT INTO system_menu(
  41 + name, permission, type, sort, parent_id,
  42 + path, icon, component, status
  43 +)
  44 +VALUES (
  45 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  46 + '', '', '', 0
  47 +);
  48 +INSERT INTO system_menu(
  49 + name, permission, type, sort, parent_id,
  50 + path, icon, component, status
  51 +)
  52 +VALUES (
  53 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  54 + '', '', '', 0
  55 +);
57 56 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/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 StudentContact {
  9 + id: number; // 编号
  10 + studentId?: number; // 学生编号
  11 + name?: string; // 名字
  12 + description?: string; // 简介
  13 + birthday?: string | Dayjs; // 出生日期
  14 + sex?: number; // 性别
  15 + enabled?: boolean; // 是否有效
  16 + avatar?: string; // 头像
  17 + video: string; // 附件
  18 + memo?: string; // 备注
  19 + }
  20 +
  21 + /** 学生班主任信息 */
  22 + export interface StudentTeacher {
  23 + id: number; // 编号
  24 + studentId?: number; // 学生编号
  25 + name?: string; // 名字
  26 + description?: string; // 简介
  27 + birthday?: string | Dayjs; // 出生日期
  28 + sex?: number; // 性别
  29 + enabled?: boolean; // 是否有效
  30 + avatar?: string; // 头像
  31 + video: string; // 附件
  32 + memo?: string; // 备注
  33 + }
  34 +
  35 + /** 学生信息 */
  36 + export interface Student {
  37 + id: number; // 编号
  38 + name?: string; // 名字
  39 + description?: string; // 简介
  40 + birthday?: string | Dayjs; // 出生日期
  41 + sex?: number; // 性别
  42 + enabled?: boolean; // 是否有效
  43 + avatar?: string; // 头像
  44 + video?: string; // 附件
  45 + memo?: string; // 备注
  46 + studentcontacts?: StudentContact[]
  47 + studentteacher?: StudentTeacher
  48 + }
  49 +}
  50 +
  51 +/** 查询学生分页 */
  52 +export function getStudentPage(params: PageParam) {
  53 + return requestClient.get<PageResult<StudentApi.Student>>('/infra/student/page', { params });
  54 +}
  55 +
  56 +/** 查询学生详情 */
  57 +export function getStudent(id: number) {
  58 + return requestClient.get<StudentApi.Student>(`/infra/student/get?id=${id}`);
  59 +}
  60 +
  61 +/** 新增学生 */
  62 +export function createStudent(data: StudentApi.Student) {
  63 + return requestClient.post('/infra/student/create', data);
  64 +}
  65 +
  66 +/** 修改学生 */
  67 +export function updateStudent(data: StudentApi.Student) {
  68 + return requestClient.put('/infra/student/update', data);
  69 +}
  70 +
  71 +/** 删除学生 */
  72 +export function deleteStudent(id: number) {
  73 + return requestClient.delete(`/infra/student/delete?id=${id}`);
  74 +}
  75 +
  76 +/** 批量删除学生 */
  77 +export function deleteStudentList(ids: number[]) {
  78 + return requestClient.delete(`/infra/student/delete-list?ids=${ids.join(',')}`)
  79 +}
  80 +
  81 +/** 导出学生 */
  82 +export function exportStudent(params: any) {
  83 + return requestClient.download('/infra/student/export-excel', { params });
  84 +}
  85 +
  86 +
  87 +// ==================== 子表(学生联系人) ====================
  88 +
  89 +/** 获得学生联系人列表 */
  90 +export function getStudentContactListByStudentId(studentId: number) {
  91 + return requestClient.get<StudentApi.StudentContact[]>(`/infra/student/student-contact/list-by-student-id?studentId=${studentId}`);
  92 +}
  93 +
  94 +// ==================== 子表(学生班主任) ====================
  95 +
  96 +/** 获得学生班主任 */
  97 +export function getStudentTeacherByStudentId(studentId: number) {
  98 + return requestClient.get<StudentApi.StudentTeacher>(`/infra/student/student-teacher/get-by-student-id?studentId=${studentId}`);
  99 +}
0 100 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/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 + import StudentContactForm from './student-contact-form.vue'
  14 + import StudentTeacherForm from './student-teacher-form.vue'
  15 +
  16 +import { $t } from '#/locales';
  17 +import { getStudent, createStudent, updateStudent } from '#/api/infra/demo';
  18 +
  19 +const emit = defineEmits(['success']);
  20 +
  21 +const formRef = ref();
  22 +const formData = ref<Partial<StudentApi.Student>>({
  23 + id: undefined,
  24 + name: undefined,
  25 + description: undefined,
  26 + birthday: undefined,
  27 + sex: undefined,
  28 + enabled: undefined,
  29 + avatar: undefined,
  30 + video: undefined,
  31 + memo: undefined,
  32 +});
  33 +const rules: Record<string, Rule[]> = {
  34 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  35 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  36 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  37 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  38 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  39 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  40 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  41 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  42 +};
  43 +const getTitle = computed(() => {
  44 + return formData.value?.id
  45 + ? $t('ui.actionTitle.edit', ['学生'])
  46 + : $t('ui.actionTitle.create', ['学生']);
  47 +});
  48 +
  49 + /** 子表的表单 */
  50 + const subTabsName = ref('studentContact')
  51 + const studentContactFormRef = ref<InstanceType<typeof StudentContactForm>>()
  52 + const studentTeacherFormRef = ref<InstanceType<typeof StudentTeacherForm>>()
  53 +
  54 +/** 重置表单 */
  55 +function resetForm() {
  56 + formData.value = {
  57 + id: undefined,
  58 + name: undefined,
  59 + description: undefined,
  60 + birthday: undefined,
  61 + sex: undefined,
  62 + enabled: undefined,
  63 + avatar: undefined,
  64 + video: undefined,
  65 + memo: undefined,
  66 + };
  67 + formRef.value?.resetFields();
  68 +}
  69 +
  70 +
  71 +const [Modal, modalApi] = useVbenModal({
  72 + async onConfirm() {
  73 + await formRef.value?.validate();
  74 + // 校验子表单
  75 + try {
  76 + await studentTeacherFormRef.value?.validate()
  77 + } catch (e) {
  78 + subTabsName.value = 'studentTeacher'
  79 + return
  80 + }
  81 + modalApi.lock();
  82 + // 提交表单
  83 + const data = formData.value as StudentApi.Student;
  84 + // 拼接子表的数据
  85 + data.studentContacts = studentContactFormRef.value?.getData();
  86 + data.studentTeacher = studentTeacherFormRef.value?.getValues();
  87 + try {
  88 + await (formData.value?.id ? updateStudent(data) : createStudent(data));
  89 + // 关闭并提示
  90 + await modalApi.close();
  91 + emit('success');
  92 + message.success({
  93 + content: $t('ui.actionMessage.operationSuccess'),
  94 + });
  95 + } finally {
  96 + modalApi.unlock();
  97 + }
  98 + },
  99 + async onOpenChange(isOpen: boolean) {
  100 + if (!isOpen) {
  101 + resetForm()
  102 + return;
  103 + }
  104 + // 加载数据
  105 + let data = modalApi.getData<StudentApi.Student>();
  106 + if (!data) {
  107 + return;
  108 + }
  109 + if (data.id) {
  110 + modalApi.lock();
  111 + try {
  112 + data = await getStudent(data.id);
  113 + } finally {
  114 + modalApi.unlock();
  115 + }
  116 + }
  117 + formData.value = data;
  118 + },
  119 +});
  120 +</script>
  121 +
  122 +<template>
  123 + <Modal :title="getTitle">
  124 + <Form
  125 + ref="formRef"
  126 + :model="formData"
  127 + :rules="rules"
  128 + :label-col="{ span: 5 }"
  129 + :wrapper-col="{ span: 18 }"
  130 + >
  131 + <Form.Item label="名字" name="name">
  132 + <Input v-model:value="formData.name" placeholder="请输入名字" />
  133 + </Form.Item>
  134 + <Form.Item label="简介" name="description">
  135 + <Textarea v-model:value="formData.description" placeholder="请输入简介" />
  136 + </Form.Item>
  137 + <Form.Item label="出生日期" name="birthday">
  138 + <DatePicker
  139 + v-model:value="formData.birthday"
  140 + valueFormat="x"
  141 + placeholder="选择出生日期"
  142 + />
  143 + </Form.Item>
  144 + <Form.Item label="性别" name="sex">
  145 + <Select v-model:value="formData.sex" placeholder="请选择性别">
  146 + <Select.Option
  147 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  148 + :key="dict.value"
  149 + :value="dict.value"
  150 + >
  151 + {{ dict.label }}
  152 + </Select.Option>
  153 + </Select>
  154 + </Form.Item>
  155 + <Form.Item label="是否有效" name="enabled">
  156 + <RadioGroup v-model:value="formData.enabled">
  157 + <Radio
  158 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  159 + :key="dict.value"
  160 + :value="dict.value"
  161 + >
  162 + {{ dict.label }}
  163 + </Radio>
  164 + </RadioGroup>
  165 + </Form.Item>
  166 + <Form.Item label="头像" name="avatar">
  167 + <ImageUpload v-model:value="formData.avatar" />
  168 + </Form.Item>
  169 + <Form.Item label="附件" name="video">
  170 + <FileUpload v-model:value="formData.video" />
  171 + </Form.Item>
  172 + <Form.Item label="备注" name="memo">
  173 + <RichTextarea v-model="formData.memo" height="500px" />
  174 + </Form.Item>
  175 + </Form>
  176 + <!-- 子表的表单 -->
  177 + <Tabs v-model:active-key="subTabsName">
  178 + <Tabs.TabPane key="studentContact" tab="学生联系人" force-render>
  179 + <StudentContactForm ref="studentContactFormRef" :student-id="formData?.id" />
  180 + </Tabs.TabPane>
  181 + <Tabs.TabPane key="studentTeacher" tab="学生班主任" force-render>
  182 + <StudentTeacherForm ref="studentTeacherFormRef" :student-id="formData?.id" />
  183 + </Tabs.TabPane>
  184 + </Tabs>
  185 + </Modal>
  186 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/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 + import StudentContactList from './modules/student-contact-list.vue'
  19 + import StudentTeacherList from './modules/student-teacher-list.vue'
  20 +
  21 +import { $t } from '#/locales';
  22 +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/demo';
  23 +
  24 + /** 子表的列表 */
  25 +const subTabsName = ref('studentContact')
  26 +
  27 +const loading = ref(true) // 列表的加载中
  28 +const list = ref<StudentApi.Student[]>([]) // 列表的数据
  29 +
  30 +const total = ref(0) // 列表的总页数
  31 +const queryParams = reactive({
  32 + pageNo: 1,
  33 + pageSize: 10,
  34 + name: undefined,
  35 + birthday: undefined,
  36 + birthday: undefined,
  37 + sex: undefined,
  38 + enabled: undefined,
  39 + createTime: undefined,
  40 +})
  41 +const queryFormRef = ref() // 搜索的表单
  42 +const exportLoading = ref(false) // 导出的加载中
  43 +
  44 +/** 查询列表 */
  45 +async function getList() {
  46 + loading.value = true
  47 + try {
  48 + const params = cloneDeep(queryParams) as any;
  49 + if (params.birthday && Array.isArray(params.birthday)) {
  50 + params.birthday = (params.birthday as string[]).join(',');
  51 + }
  52 + if (params.createTime && Array.isArray(params.createTime)) {
  53 + params.createTime = (params.createTime as string[]).join(',');
  54 + }
  55 + const data = await getStudentPage(params)
  56 + list.value = data.list
  57 + total.value = data.total
  58 + } finally {
  59 + loading.value = false
  60 + }
  61 +}
  62 +
  63 +/** 搜索按钮操作 */
  64 +function handleQuery() {
  65 + queryParams.pageNo = 1
  66 + getList()
  67 +}
  68 +
  69 +/** 重置按钮操作 */
  70 +function resetQuery() {
  71 + queryFormRef.value.resetFields()
  72 + handleQuery()
  73 +}
  74 +
  75 +const [FormModal, formModalApi] = useVbenModal({
  76 + connectedComponent: StudentForm,
  77 + destroyOnClose: true,
  78 +});
  79 +
  80 +/** 创建学生 */
  81 +function handleCreate() {
  82 + formModalApi.setData(null).open();
  83 +}
  84 +
  85 +/** 编辑学生 */
  86 +function handleEdit(row: StudentApi.Student) {
  87 + formModalApi.setData(row).open();
  88 +}
  89 +
  90 +
  91 +/** 删除学生 */
  92 +async function handleDelete(row: StudentApi.Student) {
  93 + const hideLoading = message.loading({
  94 + content: $t('ui.actionMessage.deleting', [row.id]),
  95 + duration: 0,
  96 + });
  97 + try {
  98 + await deleteStudent(row.id!);
  99 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  100 + await getList();
  101 + } finally {
  102 + hideLoading();
  103 + }
  104 +}
  105 +
  106 +/** 批量删除学生 */
  107 +async function handleDeleteBatch() {
  108 + const hideLoading = message.loading({
  109 + content: $t('ui.actionMessage.deleting'),
  110 + duration: 0,
  111 + });
  112 + try {
  113 + await deleteStudentList(checkedIds.value);
  114 + checkedIds.value = [];
  115 + message.success($t('ui.actionMessage.deleteSuccess'));
  116 + await getList();
  117 + } finally {
  118 + hideLoading();
  119 + }
  120 +}
  121 +
  122 +const checkedIds = ref<number[]>([])
  123 +function handleRowCheckboxChange({
  124 + records,
  125 +}: {
  126 + records: StudentApi.Student[];
  127 +}) {
  128 + checkedIds.value = records.map((item) => item.id!);
  129 +}
  130 +
  131 +/** 导出表格 */
  132 +async function handleExport() {
  133 +try {
  134 + exportLoading.value = true;
  135 + const data = await exportStudent(queryParams);
  136 + downloadFileFromBlobPart({ fileName: '学生.xls', source: data });
  137 +}finally {
  138 + exportLoading.value = false;
  139 +}
  140 +}
  141 +
  142 +
  143 +
  144 +/** 初始化 */
  145 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  146 +onMounted(() => {
  147 + getList();
  148 +});
  149 +</script>
  150 +
  151 +<template>
  152 + <Page auto-content-height>
  153 + <FormModal @success="getList" />
  154 +
  155 + <Card v-if="!hiddenSearchBar" class="mb-4">
  156 + <!-- 搜索工作栏 -->
  157 + <Form
  158 + :model="queryParams"
  159 + ref="queryFormRef"
  160 + layout="inline"
  161 + >
  162 + <Form.Item label="名字" name="name">
  163 + <Input
  164 + v-model:value="queryParams.name"
  165 + placeholder="请输入名字"
  166 + allowClear
  167 + @pressEnter="handleQuery"
  168 + class="w-full"
  169 + />
  170 + </Form.Item>
  171 + <Form.Item label="出生日期" name="birthday">
  172 + <DatePicker
  173 + v-model:value="queryParams.birthday"
  174 + valueFormat="YYYY-MM-DD"
  175 + placeholder="选择出生日期"
  176 + allowClear
  177 + class="w-full"
  178 + />
  179 + </Form.Item>
  180 + <Form.Item label="性别" name="sex">
  181 + <Select
  182 + v-model:value="queryParams.sex"
  183 + placeholder="请选择性别"
  184 + allowClear
  185 + class="w-full"
  186 + >
  187 + <Select.Option
  188 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  189 + :key="dict.value"
  190 + :value="dict.value"
  191 + >
  192 + {{ dict.label }}
  193 + </Select.Option>
  194 + </Select>
  195 + </Form.Item>
  196 + <Form.Item label="是否有效" name="enabled">
  197 + <Select
  198 + v-model:value="queryParams.enabled"
  199 + placeholder="请选择是否有效"
  200 + allowClear
  201 + class="w-full"
  202 + >
  203 + <Select.Option
  204 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  205 + :key="dict.value"
  206 + :value="dict.value"
  207 + >
  208 + {{ dict.label }}
  209 + </Select.Option>
  210 + </Select>
  211 + </Form.Item>
  212 + <Form.Item label="创建时间" name="createTime">
  213 + <RangePicker
  214 + v-model:value="queryParams.createTime"
  215 + v-bind="getRangePickerDefaultProps()"
  216 + class="w-full"
  217 + />
  218 + </Form.Item>
  219 + <Form.Item>
  220 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  221 + <Button class="ml-2" @click="handleQuery" type="primary">
  222 + 搜索
  223 + </Button>
  224 + </Form.Item>
  225 + </Form>
  226 + </Card>
  227 +
  228 + <!-- 列表 -->
  229 + <Card title="学生">
  230 + <template #extra>
  231 + <VbenVxeTableToolbar
  232 + ref="tableToolbarRef"
  233 + v-model:hidden-search="hiddenSearchBar"
  234 + >
  235 + <Button
  236 + class="ml-2"
  237 + :icon="h(Plus)"
  238 + type="primary"
  239 + @click="handleCreate"
  240 + v-access:code="['infra:student:create']"
  241 + >
  242 + {{ $t('ui.actionTitle.create', ['学生']) }}
  243 + </Button>
  244 + <Button
  245 + :icon="h(Download)"
  246 + type="primary"
  247 + class="ml-2"
  248 + :loading="exportLoading"
  249 + @click="handleExport"
  250 + v-access:code="['infra:student:export']"
  251 + >
  252 + {{ $t('ui.actionTitle.export') }}
  253 + </Button>
  254 + <Button
  255 + :icon="h(Trash2)"
  256 + type="primary"
  257 + danger
  258 + class="ml-2"
  259 + :disabled="isEmpty(checkedIds)"
  260 + @click="handleDeleteBatch"
  261 + v-access:code="['infra:student:delete']"
  262 + >
  263 + 批量删除
  264 + </Button>
  265 + </VbenVxeTableToolbar>
  266 + </template>
  267 + <VxeTable
  268 + ref="tableRef"
  269 + :data="list"
  270 + show-overflow
  271 + :loading="loading"
  272 + @checkboxAll="handleRowCheckboxChange"
  273 + @checkboxChange="handleRowCheckboxChange"
  274 + >
  275 + <VxeColumn type="checkbox" width="40" />
  276 + <!-- 子表的列表 -->
  277 + <VxeColumn type="expand" width="60">
  278 + <template #content="{ row }">
  279 + <!-- 子表的表单 -->
  280 + <Tabs v-model:active-key="subTabsName" class="mx-8">
  281 + <Tabs.TabPane key="studentContact" tab="学生联系人" force-render>
  282 + <StudentContactList :student-id="row?.id" />
  283 + </Tabs.TabPane>
  284 + <Tabs.TabPane key="studentTeacher" tab="学生班主任" force-render>
  285 + <StudentTeacherList :student-id="row?.id" />
  286 + </Tabs.TabPane>
  287 + </Tabs>
  288 + </template>
  289 + </VxeColumn>
  290 + <VxeColumn field="id" title="编号" align="center" />
  291 + <VxeColumn field="name" title="名字" align="center" />
  292 + <VxeColumn field="description" title="简介" align="center" />
  293 + <VxeColumn field="birthday" title="出生日期" align="center">
  294 + <template #default="{row}">
  295 + {{formatDateTime(row.birthday)}}
  296 + </template>
  297 + </VxeColumn>
  298 + <VxeColumn field="sex" title="性别" align="center">
  299 + <template #default="{row}">
  300 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  301 + </template>
  302 + </VxeColumn>
  303 + <VxeColumn field="enabled" title="是否有效" align="center">
  304 + <template #default="{row}">
  305 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  306 + </template>
  307 + </VxeColumn>
  308 + <VxeColumn field="avatar" title="头像" align="center" />
  309 + <VxeColumn field="video" title="附件" align="center" />
  310 + <VxeColumn field="memo" title="备注" align="center" />
  311 + <VxeColumn field="createTime" title="创建时间" align="center">
  312 + <template #default="{row}">
  313 + {{formatDateTime(row.createTime)}}
  314 + </template>
  315 + </VxeColumn>
  316 + <VxeColumn field="operation" title="操作" align="center">
  317 + <template #default="{row}">
  318 + <Button
  319 + size="small"
  320 + type="link"
  321 + @click="handleEdit(row)"
  322 + v-access:code="['infra:student:update']"
  323 + >
  324 + {{ $t('ui.actionTitle.edit') }}
  325 + </Button>
  326 + <Button
  327 + size="small"
  328 + type="link"
  329 + danger
  330 + class="ml-2"
  331 + @click="handleDelete(row)"
  332 + v-access:code="['infra:student:delete']"
  333 + >
  334 + {{ $t('ui.actionTitle.delete') }}
  335 + </Button>
  336 + </template>
  337 + </VxeColumn>
  338 + </VxeTable>
  339 + <!-- 分页 -->
  340 + <div class="mt-2 flex justify-end">
  341 + <Pagination
  342 + :total="total"
  343 + v-model:current="queryParams.pageNo"
  344 + v-model:page-size="queryParams.pageSize"
  345 + show-size-changer
  346 + @change="getList"
  347 + />
  348 + </div>
  349 + </Card>
  350 + </Page>
  351 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/vue/student-contact-form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +
  4 +import { computed, ref, h, onMounted, watch, nextTick } from 'vue';
  5 +
  6 +import { DICT_TYPE } from '@vben/constants';
  7 +import { getDictOptions } from '@vben/hooks';
  8 +
  9 +import { message, Tabs, Form, Input, Textarea, Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'ant-design-vue';
  10 +import { $t } from '#/locales';
  11 +
  12 + import type { VxeTableInstance } from '#/adapter/vxe-table';
  13 +import { Plus } from "@vben/icons";
  14 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  15 +import { ImageUpload, FileUpload } from "#/components/upload";
  16 +import { getStudentContactListByStudentId } from '#/api/infra/demo';
  17 +
  18 +const props = defineProps<{
  19 + studentId?: number // 学生编号(主表的关联字段)
  20 +}>()
  21 +
  22 + const list = ref<StudentApi.StudentContact[]>([]) // 列表的数据
  23 +const tableRef = ref<VxeTableInstance>();
  24 +
  25 +/** 添加学生联系人 */
  26 +async function handleAdd() {
  27 + await tableRef.value?.insertAt({} as StudentApi.StudentContact, -1);
  28 +}
  29 +
  30 +/** 删除学生联系人 */
  31 +async function handleDelete(row: StudentApi.StudentContact) {
  32 + await tableRef.value?.remove(row);
  33 +}
  34 +
  35 +/** 提供获取表格数据的方法供父组件调用 */
  36 +defineExpose({
  37 + getData: (): StudentApi.StudentContact[] => {
  38 + const data = list.value as StudentApi.StudentContact[];
  39 + const removeRecords = tableRef.value?.getRemoveRecords() as StudentApi.StudentContact[];
  40 + const insertRecords = tableRef.value?.getInsertRecords() as StudentApi.StudentContact[];
  41 + return [
  42 + ...data.filter(
  43 + (row) => !removeRecords.some((removed) => removed.id === row.id),
  44 + ),
  45 + ...insertRecords.map((row: any) => ({ ...row, id: undefined })),
  46 + ];
  47 + },
  48 +});
  49 +
  50 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  51 +watch(
  52 + () => props.studentId,
  53 + async (val) => {
  54 + if (!val) {
  55 + return;
  56 + }
  57 + list.value = await getStudentContactListByStudentId(props.studentId!);
  58 + },
  59 + { immediate: true },
  60 +);
  61 +</script>
  62 +
  63 +<template>
  64 + <VxeTable ref="tableRef" :data="list" show-overflow class="mx-4">
  65 + <VxeColumn field="name" title="名字" align="center">
  66 + <template #default="{ row }">
  67 + <Input v-model:value="row.name" />
  68 + </template>
  69 + </VxeColumn>
  70 + <VxeColumn field="description" title="简介" align="center">
  71 + <template #default="{ row }">
  72 + <Textarea v-model:value="row.description" />
  73 + </template>
  74 + </VxeColumn>
  75 + <VxeColumn field="birthday" title="出生日期" align="center">
  76 + <template #default="{ row }">
  77 + <DatePicker
  78 + v-model:value="row.birthday"
  79 + :showTime="true"
  80 + format="YYYY-MM-DD HH:mm:ss"
  81 + valueFormat='x'
  82 + />
  83 + </template>
  84 + </VxeColumn>
  85 + <VxeColumn field="sex" title="性别" align="center">
  86 + <template #default="{ row }">
  87 + <Select v-model:value="row.sex" placeholder="请选择性别">
  88 + <Select.Option
  89 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')"
  90 + :key="dict.value"
  91 + :value="dict.value"
  92 + >
  93 + {{ dict.label }}
  94 + </Select.Option>
  95 + </Select>
  96 + </template>
  97 + </VxeColumn>
  98 + <VxeColumn field="enabled" title="是否有效" align="center">
  99 + <template #default="{ row }">
  100 + <RadioGroup v-model:value="row.enabled">
  101 + <Radio
  102 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'boolean')"
  103 + :key="dict.value"
  104 + :value="dict.value"
  105 + >
  106 + {{ dict.label }}
  107 + </Radio>
  108 + </RadioGroup>
  109 + </template>
  110 + </VxeColumn>
  111 + <VxeColumn field="avatar" title="头像" align="center">
  112 + <template #default="{ row }">
  113 + <ImageUpload v-model:value="row.avatar" />
  114 + </template>
  115 + </VxeColumn>
  116 + <VxeColumn field="video" title="附件" align="center">
  117 + <template #default="{ row }">
  118 + <FileUpload v-model:value="row.video" />
  119 + </template>
  120 + </VxeColumn>
  121 + <VxeColumn field="memo" title="备注" align="center">
  122 + <template #default="{ row }">
  123 + <Textarea v-model:value="row.memo" />
  124 + </template>
  125 + </VxeColumn>
  126 + <VxeColumn field="operation" title="操作" align="center">
  127 + <template #default="{ row }">
  128 + <Button
  129 + size="small"
  130 + type="link"
  131 + danger
  132 + @click="handleDelete(row)"
  133 + v-access:code="['infra:student:delete']"
  134 + >
  135 + {{ $t('ui.actionTitle.delete') }}
  136 + </Button>
  137 + </template>
  138 + </VxeColumn>
  139 + </VxeTable>
  140 + <div class="flex justify-center mt-4">
  141 + <Button :icon="h(Plus)" type="primary" ghost @click="handleAdd" v-access:code="['infra:student:create']">
  142 + {{ $t('ui.actionTitle.create', ['学生联系人']) }}
  143 + </Button>
  144 + </div>
  145 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/vue/student-contact-list 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +import type { VxeTableInstance } from '#/adapter/vxe-table';
  4 +
  5 +import { reactive, ref, h, nextTick, watch, onMounted } from 'vue';
  6 +
  7 +import { DICT_TYPE } from '@vben/constants';
  8 +import { getDictOptions } from '@vben/hooks';
  9 +
  10 +import { DictTag } from '#/components/dict-tag';
  11 +import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
  12 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  13 +import { formatDateTime } from '@vben/utils';
  14 +
  15 +
  16 + import { getStudentContactListByStudentId } from '#/api/infra/demo';
  17 +
  18 +const props = defineProps<{
  19 + studentId?: number // 学生编号(主表的关联字段)
  20 +}>()
  21 +
  22 +
  23 +const loading = ref(true) // 列表的加载中
  24 +const list = ref<StudentApi.StudentContact[]>([]) // 列表的数据
  25 + /** 查询列表 */
  26 +async function getList() {
  27 + loading.value = true
  28 + try {
  29 + if (!props.studentId){
  30 + return []
  31 + }
  32 + list.value = await getStudentContactListByStudentId(props.studentId!);
  33 + } finally {
  34 + loading.value = false
  35 + }
  36 +}
  37 +
  38 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  39 +watch(
  40 + () => props.studentId,
  41 + async (val) => {
  42 + if (!val) {
  43 + return;
  44 + }
  45 + await nextTick();
  46 + await getList()
  47 + },
  48 + { immediate: true },
  49 +);
  50 +
  51 +</script>
  52 +
  53 +<template>
  54 + <Card title="学生联系人列表">
  55 + <VxeTable
  56 + :data="list"
  57 + show-overflow
  58 + :loading="loading"
  59 + >
  60 + <VxeColumn field="id" title="编号" align="center" />
  61 + <VxeColumn field="studentId" title="学生编号" align="center" />
  62 + <VxeColumn field="name" title="名字" align="center" />
  63 + <VxeColumn field="description" title="简介" align="center" />
  64 + <VxeColumn field="birthday" title="出生日期" align="center">
  65 + <template #default="{row}">
  66 + {{formatDateTime(row.birthday)}}
  67 + </template>
  68 + </VxeColumn>
  69 + <VxeColumn field="sex" title="性别" align="center">
  70 + <template #default="{row}">
  71 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  72 + </template>
  73 + </VxeColumn>
  74 + <VxeColumn field="enabled" title="是否有效" align="center">
  75 + <template #default="{row}">
  76 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  77 + </template>
  78 + </VxeColumn>
  79 + <VxeColumn field="avatar" title="头像" align="center" />
  80 + <VxeColumn field="video" title="附件" align="center" />
  81 + <VxeColumn field="memo" title="备注" align="center" />
  82 + <VxeColumn field="createTime" title="创建时间" align="center">
  83 + <template #default="{row}">
  84 + {{formatDateTime(row.createTime)}}
  85 + </template>
  86 + </VxeColumn>
  87 + </VxeTable>
  88 + </Card>
  89 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/vue/student-teacher-form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +
  4 +import { computed, ref, h, onMounted, watch, nextTick } from 'vue';
  5 +
  6 +import { DICT_TYPE } from '@vben/constants';
  7 +import { getDictOptions } from '@vben/hooks';
  8 +
  9 +import { message, Tabs, Form, Input, Textarea, Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'ant-design-vue';
  10 +import { $t } from '#/locales';
  11 +
  12 +import type { Rule } from 'ant-design-vue/es/form';
  13 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  14 +import { ImageUpload, FileUpload } from "#/components/upload";
  15 +import { getStudentTeacherByStudentId } from '#/api/infra/demo';
  16 +
  17 +const props = defineProps<{
  18 + studentId?: number // 学生编号(主表的关联字段)
  19 +}>()
  20 +
  21 +const formRef = ref();
  22 +const formData = ref<Partial<StudentApi.StudentTeacher>>({
  23 + id: undefined,
  24 + studentId: undefined,
  25 + name: undefined,
  26 + description: undefined,
  27 + birthday: undefined,
  28 + sex: undefined,
  29 + enabled: undefined,
  30 + avatar: undefined,
  31 + video: undefined,
  32 + memo: undefined,
  33 +});
  34 +const rules: Record<string, Rule[]> = {
  35 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  36 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  37 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  38 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  39 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  40 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  41 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  42 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  43 +};
  44 +/** 暴露出表单校验方法和表单值获取方法 */
  45 +defineExpose({
  46 + validate: async () => await formRef.value?.validate(),
  47 + getValues: ()=> formData.value,
  48 +});
  49 +
  50 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  51 +watch(
  52 + () => props.studentId,
  53 + async (val) => {
  54 + if (!val) {
  55 + return;
  56 + }
  57 + await nextTick();
  58 + formData.value = await getStudentTeacherByStudentId(props.studentId!);
  59 + },
  60 + { immediate: true },
  61 +);
  62 +</script>
  63 +
  64 +<template>
  65 + <Form
  66 + ref="formRef"
  67 + class="mx-4"
  68 + :model="formData"
  69 + :rules="rules"
  70 + :label-col="{ span: 5 }"
  71 + :wrapper-col="{ span: 18 }"
  72 + >
  73 + <Form.Item label="名字" name="name">
  74 + <Input v-model:value="formData.name" placeholder="请输入名字" />
  75 + </Form.Item>
  76 + <Form.Item label="简介" name="description">
  77 + <Textarea v-model:value="formData.description" placeholder="请输入简介" />
  78 + </Form.Item>
  79 + <Form.Item label="出生日期" name="birthday">
  80 + <DatePicker
  81 + v-model:value="formData.birthday"
  82 + valueFormat="x"
  83 + placeholder="选择出生日期"
  84 + />
  85 + </Form.Item>
  86 + <Form.Item label="性别" name="sex">
  87 + <Select v-model:value="formData.sex" placeholder="请选择性别">
  88 + <Select.Option
  89 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  90 + :key="dict.value"
  91 + :value="dict.value"
  92 + >
  93 + {{ dict.label }}
  94 + </Select.Option>
  95 + </Select>
  96 + </Form.Item>
  97 + <Form.Item label="是否有效" name="enabled">
  98 + <RadioGroup v-model:value="formData.enabled">
  99 + <Radio
  100 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  101 + :key="dict.value"
  102 + :value="dict.value"
  103 + >
  104 + {{ dict.label }}
  105 + </Radio>
  106 + </RadioGroup>
  107 + </Form.Item>
  108 + <Form.Item label="头像" name="avatar">
  109 + <ImageUpload v-model:value="formData.avatar" />
  110 + </Form.Item>
  111 + <Form.Item label="附件" name="video">
  112 + <FileUpload v-model:value="formData.video" />
  113 + </Form.Item>
  114 + <Form.Item label="备注" name="memo">
  115 + <RichTextarea v-model="formData.memo" height="500px" />
  116 + </Form.Item>
  117 + </Form>
  118 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/vue/student-teacher-list 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +import type { VxeTableInstance } from '#/adapter/vxe-table';
  4 +
  5 +import { reactive, ref, h, nextTick, watch, onMounted } from 'vue';
  6 +
  7 +import { DICT_TYPE } from '@vben/constants';
  8 +import { getDictOptions } from '@vben/hooks';
  9 +
  10 +import { DictTag } from '#/components/dict-tag';
  11 +import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
  12 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  13 +import { formatDateTime } from '@vben/utils';
  14 +
  15 +
  16 +import { getStudentTeacherByStudentId } from '#/api/infra/demo';
  17 +
  18 +const props = defineProps<{
  19 + studentId?: number // 学生编号(主表的关联字段)
  20 +}>()
  21 +
  22 +
  23 +const loading = ref(true) // 列表的加载中
  24 +const list = ref<StudentApi.StudentTeacher[]>([]) // 列表的数据
  25 + /** 查询列表 */
  26 +async function getList() {
  27 + loading.value = true
  28 + try {
  29 + if (!props.studentId){
  30 + return []
  31 + }
  32 + list.value = [await getStudentTeacherByStudentId(props.studentId!)];
  33 + } finally {
  34 + loading.value = false
  35 + }
  36 +}
  37 +
  38 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  39 +watch(
  40 + () => props.studentId,
  41 + async (val) => {
  42 + if (!val) {
  43 + return;
  44 + }
  45 + await nextTick();
  46 + await getList()
  47 + },
  48 + { immediate: true },
  49 +);
  50 +
  51 +</script>
  52 +
  53 +<template>
  54 + <Card title="学生班主任列表">
  55 + <VxeTable
  56 + :data="list"
  57 + show-overflow
  58 + :loading="loading"
  59 + >
  60 + <VxeColumn field="id" title="编号" align="center" />
  61 + <VxeColumn field="studentId" title="学生编号" align="center" />
  62 + <VxeColumn field="name" title="名字" align="center" />
  63 + <VxeColumn field="description" title="简介" align="center" />
  64 + <VxeColumn field="birthday" title="出生日期" align="center">
  65 + <template #default="{row}">
  66 + {{formatDateTime(row.birthday)}}
  67 + </template>
  68 + </VxeColumn>
  69 + <VxeColumn field="sex" title="性别" align="center">
  70 + <template #default="{row}">
  71 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  72 + </template>
  73 + </VxeColumn>
  74 + <VxeColumn field="enabled" title="是否有效" align="center">
  75 + <template #default="{row}">
  76 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  77 + </template>
  78 + </VxeColumn>
  79 + <VxeColumn field="avatar" title="头像" align="center" />
  80 + <VxeColumn field="video" title="附件" align="center" />
  81 + <VxeColumn field="memo" title="备注" align="center" />
  82 + <VxeColumn field="createTime" title="创建时间" align="center">
  83 + <template #default="{row}">
  84 + {{formatDateTime(row.createTime)}}
  85 + </template>
  86 + </VxeColumn>
  87 + </VxeTable>
  88 + </Card>
  89 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/xml/InfraStudentMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/xml/InfraStudentMapper
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/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/InfraStudentController",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentDO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentContactDO",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentTeacherDO",
  21 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.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" : "java/InfraStudentContactMapper",
  27 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentTeacherMapper",
  30 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java"
  31 +}, {
  32 + "contentPath" : "xml/InfraStudentMapper",
  33 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImpl",
  36 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  37 +}, {
  38 + "contentPath" : "java/InfraStudentService",
  39 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  40 +}, {
  41 + "contentPath" : "java/InfraStudentServiceImplTest",
  42 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  43 +}, {
  44 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  45 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  46 +}, {
  47 + "contentPath" : "sql/sql",
  48 + "filePath" : "sql/sql.sql"
  49 +}, {
  50 + "contentPath" : "sql/h2",
  51 + "filePath" : "sql/h2.sql"
  52 +}, {
  53 + "contentPath" : "vue/index",
  54 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  55 +}, {
  56 + "contentPath" : "vue/form",
  57 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  58 +}, {
  59 + "contentPath" : "ts/index",
  60 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  61 +}, {
  62 + "contentPath" : "vue/student-contact-form",
  63 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-contact-form.vue"
  64 +}, {
  65 + "contentPath" : "vue/student-teacher-form",
  66 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/student-teacher-form.vue"
  67 +} ]
0 68 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/ErrorCodeConstants_手动操作 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/ErrorCodeConstants_手动操作
1   -// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
2   -// ========== 学生 TODO 补充编号 ==========
3   -ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
4 1 \ No newline at end of file
  2 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  3 +// ========== 学生 TODO 补充编号 ==========
  4 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
5 5 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentContactDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentContactDO
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentContactMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentContactMapper
... ... @@ -25,4 +25,8 @@ public interface InfraStudentContactMapper extends BaseMapperX&lt;InfraStudentConta
25 25 return delete(InfraStudentContactDO::getStudentId, studentId);
26 26 }
27 27  
  28 + default int deleteByStudentIds(List<Long> studentIds) {
  29 + return deleteBatch(InfraStudentContactDO::getStudentId, studentIds);
  30 + }
  31 +
28 32 }
29 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentController renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentController
1 1 package cn.iocoder.yudao.module.infra.controller.admin.demo;
2 2  
3 3 import org.springframework.web.bind.annotation.*;
4   -import javax.annotation.Resource;
  4 +import jakarta.annotation.Resource;
5 5 import org.springframework.validation.annotation.Validated;
6 6 import org.springframework.security.access.prepost.PreAuthorize;
7 7 import io.swagger.v3.oas.annotations.tags.Tag;
8 8 import io.swagger.v3.oas.annotations.Parameter;
9 9 import io.swagger.v3.oas.annotations.Operation;
10 10  
11   -import javax.validation.constraints.*;
12   -import javax.validation.*;
13   -import javax.servlet.http.*;
  11 +import jakarta.validation.constraints.*;
  12 +import jakarta.validation.*;
  13 +import jakarta.servlet.http.*;
14 14 import java.util.*;
15 15 import java.io.IOException;
16 16  
... ... @@ -22,8 +22,8 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 22  
23 23 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
24 24  
25   -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
26   -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  25 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  26 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
27 27  
28 28 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
29 29 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
... ... @@ -64,6 +64,15 @@ public class InfraStudentController {
64 64 return success(true);
65 65 }
66 66  
  67 + @DeleteMapping("/delete-list")
  68 + @Parameter(name = "ids", description = "编号", required = true)
  69 + @Operation(summary = "批量删除学生")
  70 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  71 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  72 + studentService.deleteStudentListByIds(ids);
  73 + return success(true);
  74 + }
  75 +
67 76 @GetMapping("/get")
68 77 @Operation(summary = "获得学生")
69 78 @Parameter(name = "id", description = "编号", required = true, example = "1024")
... ... @@ -84,7 +93,7 @@ public class InfraStudentController {
84 93 @GetMapping("/export-excel")
85 94 @Operation(summary = "导出学生 Excel")
86 95 @PreAuthorize("@ss.hasPermission('infra:student:export')")
87   - @OperateLog(type = EXPORT)
  96 + @ApiAccessLog(operateType = EXPORT)
88 97 public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
89 98 HttpServletResponse response) throws IOException {
90 99 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentDO
... ... @@ -64,4 +64,5 @@ public class InfraStudentDO extends BaseDO {
64 64 */
65 65 private String memo;
66 66  
  67 +
67 68 }
68 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentMapper
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentPageReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentPageReqVO
... ... @@ -11,8 +11,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
11 11  
12 12 @Schema(description = "管理后台 - 学生分页 Request VO")
13 13 @Data
14   -@EqualsAndHashCode(callSuper = true)
15   -@ToString(callSuper = true)
16 14 public class InfraStudentPageReqVO extends PageParam {
17 15  
18 16 @Schema(description = "名字", example = "芋头")
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentRespVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentRespVO
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import java.util.*;
7 6 import org.springframework.format.annotation.DateTimeFormat;
8 7 import java.time.LocalDateTime;
9 8 import cn.idev.excel.annotation.*;
... ... @@ -57,4 +56,4 @@ public class InfraStudentRespVO {
57 56 @ExcelProperty("创建时间")
58 57 private LocalDateTime createTime;
59 58  
60 59 -}
  60 +}
61 61 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentSaveReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentSaveReqVO
... ... @@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import javax.validation.constraints.*;
7   -import java.util.*;
  6 +import jakarta.validation.constraints.*;
8 7 import org.springframework.format.annotation.DateTimeFormat;
9 8 import java.time.LocalDateTime;
10 9 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentService renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentService
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
3 3 import java.util.*;
4   -import javax.validation.*;
  4 +import jakarta.validation.*;
5 5 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
6 6 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
7 7 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
... ... @@ -39,6 +39,13 @@ public interface InfraStudentService {
39 39 void deleteStudent(Long id);
40 40  
41 41 /**
  42 + * 批量删除学生
  43 + *
  44 + * @param ids 编号
  45 + */
  46 + void deleteStudentListByIds(List<Long> ids);
  47 +
  48 + /**
42 49 * 获得学生
43 50 *
44 51 * @param id 编号
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImpl renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentServiceImpl
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import org.springframework.stereotype.Service;
4   -import javax.annotation.Resource;
  5 +import jakarta.annotation.Resource;
5 6 import org.springframework.validation.annotation.Validated;
6 7 import org.springframework.transaction.annotation.Transactional;
7 8  
... ... @@ -19,6 +20,8 @@ import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper;
19 20 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper;
20 21  
21 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  23 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
22 25 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
23 26  
24 27 /**
... ... @@ -44,6 +47,7 @@ public class InfraStudentServiceImpl implements InfraStudentService {
44 47 InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
45 48 studentMapper.insert(student);
46 49  
  50 +
47 51 // 插入子表
48 52 createStudentContactList(student.getId(), createReqVO.getStudentContacts());
49 53 createStudentTeacher(student.getId(), createReqVO.getStudentTeacher());
... ... @@ -78,6 +82,18 @@ public class InfraStudentServiceImpl implements InfraStudentService {
78 82 deleteStudentTeacherByStudentId(id);
79 83 }
80 84  
  85 + @Override
  86 + @Transactional(rollbackFor = Exception.class)
  87 + public void deleteStudentListByIds(List<Long> ids) {
  88 + // 删除
  89 + studentMapper.deleteByIds(ids);
  90 +
  91 + // 删除子表
  92 + deleteStudentContactByStudentIds(ids);
  93 + deleteStudentTeacherByStudentIds(ids);
  94 + }
  95 +
  96 +
81 97 private void validateStudentExists(Long id) {
82 98 if (studentMapper.selectById(id) == null) {
83 99 throw exception(STUDENT_NOT_EXISTS);
... ... @@ -102,20 +118,44 @@ public class InfraStudentServiceImpl implements InfraStudentService {
102 118 }
103 119  
104 120 private void createStudentContactList(Long studentId, List<InfraStudentContactDO> list) {
105   - list.forEach(o -> o.setStudentId(studentId));
  121 + if (CollUtil.isEmpty(list)) {
  122 + return;
  123 + }
  124 + list.forEach(o -> o.setStudentId(studentId).clean());
106 125 studentContactMapper.insertBatch(list);
107 126 }
108 127  
109 128 private void updateStudentContactList(Long studentId, List<InfraStudentContactDO> list) {
110   - deleteStudentContactByStudentId(studentId);
111   - list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新
112   - createStudentContactList(studentId, list);
  129 + list.forEach(o -> o.setStudentId(studentId).clean());
  130 + List<InfraStudentContactDO> oldList = studentContactMapper.selectListByStudentId(studentId);
  131 + List<List<InfraStudentContactDO>> diffList = diffList(oldList, list, (oldVal, newVal) -> {
  132 + boolean same = ObjectUtil.equal(oldVal.getId(), newVal.getId());
  133 + if (same) {
  134 + newVal.setId(oldVal.getId()).clean(); // 解决更新情况下:updateTime 不更新
  135 + }
  136 + return same;
  137 + });
  138 +
  139 + // 第二步,批量添加、修改、删除
  140 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  141 + studentContactMapper.insertBatch(diffList.get(0));
  142 + }
  143 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  144 + studentContactMapper.updateBatch(diffList.get(1));
  145 + }
  146 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  147 + studentContactMapper.deleteByIds(convertList(diffList.get(2), InfraStudentContactDO::getId));
  148 + }
113 149 }
114 150  
115 151 private void deleteStudentContactByStudentId(Long studentId) {
116 152 studentContactMapper.deleteByStudentId(studentId);
117 153 }
118 154  
  155 + private void deleteStudentContactByStudentIds(List<Long> studentIds) {
  156 + studentContactMapper.deleteByStudentIds(studentIds);
  157 + }
  158 +
119 159 // ==================== 子表(学生班主任) ====================
120 160  
121 161 @Override
... ... @@ -135,8 +175,7 @@ public class InfraStudentServiceImpl implements InfraStudentService {
135 175 if (studentTeacher == null) {
136 176 return;
137 177 }
138   - studentTeacher.setStudentId(studentId);
139   - studentTeacher.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新
  178 + studentTeacher.setStudentId(studentId).clean();// 解决更新情况下:updateTime 不更新
140 179 studentTeacherMapper.insertOrUpdate(studentTeacher);
141 180 }
142 181  
... ... @@ -144,4 +183,8 @@ public class InfraStudentServiceImpl implements InfraStudentService {
144 183 studentTeacherMapper.deleteByStudentId(studentId);
145 184 }
146 185  
  186 + private void deleteStudentTeacherByStudentIds(List<Long> studentIds) {
  187 + studentTeacherMapper.deleteByStudentIds(studentIds);
  188 + }
  189 +
147 190 }
148 191 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImplTest renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentServiceImplTest
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.infra.service.demo;
3 3 import org.junit.jupiter.api.Disabled;
4 4 import org.junit.jupiter.api.Test;
5 5  
6   -import javax.annotation.Resource;
  6 +import jakarta.annotation.Resource;
7 7  
8 8 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
9 9  
... ... @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
12 12 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
13 13 import cn.iocoder.yudao.framework.common.pojo.PageResult;
14 14  
15   -import javax.annotation.Resource;
  15 +import jakarta.annotation.Resource;
16 16 import org.springframework.context.annotation.Import;
17 17 import java.util.*;
18 18 import java.time.LocalDateTime;
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentTeacherDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentTeacherDO
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentTeacherMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/java/InfraStudentTeacherMapper
... ... @@ -25,4 +25,8 @@ public interface InfraStudentTeacherMapper extends BaseMapperX&lt;InfraStudentTeach
25 25 return delete(InfraStudentTeacherDO::getStudentId, studentId);
26 26 }
27 27  
  28 + default int deleteByStudentIds(List<Long> studentIds) {
  29 + return deleteBatch(InfraStudentTeacherDO::getStudentId, studentIds);
  30 + }
  31 +
28 32 }
29 33 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/sql/h2 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/sql/h2
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/sql/sql renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/sql/sql
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   --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
13   -SELECT @parentId := LAST_INSERT_ID();
14   -
15   --- 按钮 SQL
16   -INSERT INTO system_menu(
17   - name, permission, type, sort, parent_id,
18   - path, icon, component, status
19   -)
20   -VALUES (
21   - '学生查询', 'infra:student:query', 3, 1, @parentId,
22   - '', '', '', 0
23   -);
24   -INSERT INTO system_menu(
25   - name, permission, type, sort, parent_id,
26   - path, icon, component, status
27   -)
28   -VALUES (
29   - '学生创建', 'infra:student:create', 3, 2, @parentId,
30   - '', '', '', 0
31   -);
32   -INSERT INTO system_menu(
33   - name, permission, type, sort, parent_id,
34   - path, icon, component, status
35   -)
36   -VALUES (
37   - '学生更新', 'infra:student:update', 3, 3, @parentId,
38   - '', '', '', 0
39   -);
40   -INSERT INTO system_menu(
41   - name, permission, type, sort, parent_id,
42   - path, icon, component, status
43   -)
44   -VALUES (
45   - '学生删除', 'infra:student:delete', 3, 4, @parentId,
46   - '', '', '', 0
47   -);
48   -INSERT INTO system_menu(
49   - name, permission, type, sort, parent_id,
50   - path, icon, component, status
51   -)
52   -VALUES (
53   - '学生导出', 'infra:student:export', 3, 5, @parentId,
54   - '', '', '', 0
55   -);
56 1 \ No newline at end of file
  2 +-- 菜单 SQL
  3 +INSERT INTO system_menu(
  4 + name, permission, type, sort, parent_id,
  5 + path, icon, component, status, component_name
  6 +)
  7 +VALUES (
  8 + '学生管理', '', 2, 0, 888,
  9 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  10 +);
  11 +
  12 +-- 按钮父菜单ID
  13 +SELECT @parentId := LAST_INSERT_ID();
  14 +
  15 +-- 按钮 SQL
  16 +INSERT INTO system_menu(
  17 + name, permission, type, sort, parent_id,
  18 + path, icon, component, status
  19 +)
  20 +VALUES (
  21 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  22 + '', '', '', 0
  23 +);
  24 +INSERT INTO system_menu(
  25 + name, permission, type, sort, parent_id,
  26 + path, icon, component, status
  27 +)
  28 +VALUES (
  29 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  30 + '', '', '', 0
  31 +);
  32 +INSERT INTO system_menu(
  33 + name, permission, type, sort, parent_id,
  34 + path, icon, component, status
  35 +)
  36 +VALUES (
  37 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  38 + '', '', '', 0
  39 +);
  40 +INSERT INTO system_menu(
  41 + name, permission, type, sort, parent_id,
  42 + path, icon, component, status
  43 +)
  44 +VALUES (
  45 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  46 + '', '', '', 0
  47 +);
  48 +INSERT INTO system_menu(
  49 + name, permission, type, sort, parent_id,
  50 + path, icon, component, status
  51 +)
  52 +VALUES (
  53 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  54 + '', '', '', 0
  55 +);
57 56 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/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 StudentContact {
  9 + id: number; // 编号
  10 + studentId?: number; // 学生编号
  11 + name?: string; // 名字
  12 + description?: string; // 简介
  13 + birthday?: string | Dayjs; // 出生日期
  14 + sex?: number; // 性别
  15 + enabled?: boolean; // 是否有效
  16 + avatar?: string; // 头像
  17 + video: string; // 附件
  18 + memo?: string; // 备注
  19 + }
  20 +
  21 + /** 学生班主任信息 */
  22 + export interface StudentTeacher {
  23 + id: number; // 编号
  24 + studentId?: number; // 学生编号
  25 + name?: string; // 名字
  26 + description?: string; // 简介
  27 + birthday?: string | Dayjs; // 出生日期
  28 + sex?: number; // 性别
  29 + enabled?: boolean; // 是否有效
  30 + avatar?: string; // 头像
  31 + video: string; // 附件
  32 + memo?: string; // 备注
  33 + }
  34 +
  35 + /** 学生信息 */
  36 + export interface Student {
  37 + id: number; // 编号
  38 + name?: string; // 名字
  39 + description?: string; // 简介
  40 + birthday?: string | Dayjs; // 出生日期
  41 + sex?: number; // 性别
  42 + enabled?: boolean; // 是否有效
  43 + avatar?: string; // 头像
  44 + video?: string; // 附件
  45 + memo?: string; // 备注
  46 + studentcontacts?: StudentContact[]
  47 + studentteacher?: StudentTeacher
  48 + }
  49 +}
  50 +
  51 +/** 查询学生分页 */
  52 +export function getStudentPage(params: PageParam) {
  53 + return requestClient.get<PageResult<StudentApi.Student>>('/infra/student/page', { params });
  54 +}
  55 +
  56 +/** 查询学生详情 */
  57 +export function getStudent(id: number) {
  58 + return requestClient.get<StudentApi.Student>(`/infra/student/get?id=${id}`);
  59 +}
  60 +
  61 +/** 新增学生 */
  62 +export function createStudent(data: StudentApi.Student) {
  63 + return requestClient.post('/infra/student/create', data);
  64 +}
  65 +
  66 +/** 修改学生 */
  67 +export function updateStudent(data: StudentApi.Student) {
  68 + return requestClient.put('/infra/student/update', data);
  69 +}
  70 +
  71 +/** 删除学生 */
  72 +export function deleteStudent(id: number) {
  73 + return requestClient.delete(`/infra/student/delete?id=${id}`);
  74 +}
  75 +
  76 +/** 批量删除学生 */
  77 +export function deleteStudentList(ids: number[]) {
  78 + return requestClient.delete(`/infra/student/delete-list?ids=${ids.join(',')}`)
  79 +}
  80 +
  81 +/** 导出学生 */
  82 +export function exportStudent(params: any) {
  83 + return requestClient.download('/infra/student/export-excel', { params });
  84 +}
  85 +
  86 +
  87 +// ==================== 子表(学生联系人) ====================
  88 +
  89 +/** 获得学生联系人列表 */
  90 +export function getStudentContactListByStudentId(studentId: number) {
  91 + return requestClient.get<StudentApi.StudentContact[]>(`/infra/student/student-contact/list-by-student-id?studentId=${studentId}`);
  92 +}
  93 +
  94 +// ==================== 子表(学生班主任) ====================
  95 +
  96 +/** 获得学生班主任 */
  97 +export function getStudentTeacherByStudentId(studentId: number) {
  98 + return requestClient.get<StudentApi.StudentTeacher>(`/infra/student/student-teacher/get-by-student-id?studentId=${studentId}`);
  99 +}
0 100 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/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 + import StudentContactForm from './student-contact-form.vue'
  14 + import StudentTeacherForm from './student-teacher-form.vue'
  15 +
  16 +import { $t } from '#/locales';
  17 +import { getStudent, createStudent, updateStudent } from '#/api/infra/demo';
  18 +
  19 +const emit = defineEmits(['success']);
  20 +
  21 +const formRef = ref();
  22 +const formData = ref<Partial<StudentApi.Student>>({
  23 + id: undefined,
  24 + name: undefined,
  25 + description: undefined,
  26 + birthday: undefined,
  27 + sex: undefined,
  28 + enabled: undefined,
  29 + avatar: undefined,
  30 + video: undefined,
  31 + memo: undefined,
  32 +});
  33 +const rules: Record<string, Rule[]> = {
  34 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  35 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  36 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  37 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  38 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  39 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  40 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  41 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  42 +};
  43 +const getTitle = computed(() => {
  44 + return formData.value?.id
  45 + ? $t('ui.actionTitle.edit', ['学生'])
  46 + : $t('ui.actionTitle.create', ['学生']);
  47 +});
  48 +
  49 + /** 子表的表单 */
  50 + const subTabsName = ref('studentContact')
  51 + const studentContactFormRef = ref<InstanceType<typeof StudentContactForm>>()
  52 + const studentTeacherFormRef = ref<InstanceType<typeof StudentTeacherForm>>()
  53 +
  54 +/** 重置表单 */
  55 +function resetForm() {
  56 + formData.value = {
  57 + id: undefined,
  58 + name: undefined,
  59 + description: undefined,
  60 + birthday: undefined,
  61 + sex: undefined,
  62 + enabled: undefined,
  63 + avatar: undefined,
  64 + video: undefined,
  65 + memo: undefined,
  66 + };
  67 + formRef.value?.resetFields();
  68 +}
  69 +
  70 +
  71 +const [Modal, modalApi] = useVbenModal({
  72 + async onConfirm() {
  73 + await formRef.value?.validate();
  74 + // 校验子表单
  75 + try {
  76 + await studentTeacherFormRef.value?.validate()
  77 + } catch (e) {
  78 + subTabsName.value = 'studentTeacher'
  79 + return
  80 + }
  81 + modalApi.lock();
  82 + // 提交表单
  83 + const data = formData.value as StudentApi.Student;
  84 + // 拼接子表的数据
  85 + data.studentContacts = studentContactFormRef.value?.getData();
  86 + data.studentTeacher = studentTeacherFormRef.value?.getValues();
  87 + try {
  88 + await (formData.value?.id ? updateStudent(data) : createStudent(data));
  89 + // 关闭并提示
  90 + await modalApi.close();
  91 + emit('success');
  92 + message.success({
  93 + content: $t('ui.actionMessage.operationSuccess'),
  94 + });
  95 + } finally {
  96 + modalApi.unlock();
  97 + }
  98 + },
  99 + async onOpenChange(isOpen: boolean) {
  100 + if (!isOpen) {
  101 + resetForm()
  102 + return;
  103 + }
  104 + // 加载数据
  105 + let data = modalApi.getData<StudentApi.Student>();
  106 + if (!data) {
  107 + return;
  108 + }
  109 + if (data.id) {
  110 + modalApi.lock();
  111 + try {
  112 + data = await getStudent(data.id);
  113 + } finally {
  114 + modalApi.unlock();
  115 + }
  116 + }
  117 + formData.value = data;
  118 + },
  119 +});
  120 +</script>
  121 +
  122 +<template>
  123 + <Modal :title="getTitle">
  124 + <Form
  125 + ref="formRef"
  126 + :model="formData"
  127 + :rules="rules"
  128 + :label-col="{ span: 5 }"
  129 + :wrapper-col="{ span: 18 }"
  130 + >
  131 + <Form.Item label="名字" name="name">
  132 + <Input v-model:value="formData.name" placeholder="请输入名字" />
  133 + </Form.Item>
  134 + <Form.Item label="简介" name="description">
  135 + <Textarea v-model:value="formData.description" placeholder="请输入简介" />
  136 + </Form.Item>
  137 + <Form.Item label="出生日期" name="birthday">
  138 + <DatePicker
  139 + v-model:value="formData.birthday"
  140 + valueFormat="x"
  141 + placeholder="选择出生日期"
  142 + />
  143 + </Form.Item>
  144 + <Form.Item label="性别" name="sex">
  145 + <Select v-model:value="formData.sex" placeholder="请选择性别">
  146 + <Select.Option
  147 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  148 + :key="dict.value"
  149 + :value="dict.value"
  150 + >
  151 + {{ dict.label }}
  152 + </Select.Option>
  153 + </Select>
  154 + </Form.Item>
  155 + <Form.Item label="是否有效" name="enabled">
  156 + <RadioGroup v-model:value="formData.enabled">
  157 + <Radio
  158 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  159 + :key="dict.value"
  160 + :value="dict.value"
  161 + >
  162 + {{ dict.label }}
  163 + </Radio>
  164 + </RadioGroup>
  165 + </Form.Item>
  166 + <Form.Item label="头像" name="avatar">
  167 + <ImageUpload v-model:value="formData.avatar" />
  168 + </Form.Item>
  169 + <Form.Item label="附件" name="video">
  170 + <FileUpload v-model:value="formData.video" />
  171 + </Form.Item>
  172 + <Form.Item label="备注" name="memo">
  173 + <RichTextarea v-model="formData.memo" height="500px" />
  174 + </Form.Item>
  175 + </Form>
  176 + <!-- 子表的表单 -->
  177 + <Tabs v-model:active-key="subTabsName">
  178 + <Tabs.TabPane key="studentContact" tab="学生联系人" force-render>
  179 + <StudentContactForm ref="studentContactFormRef" :student-id="formData?.id" />
  180 + </Tabs.TabPane>
  181 + <Tabs.TabPane key="studentTeacher" tab="学生班主任" force-render>
  182 + <StudentTeacherForm ref="studentTeacherFormRef" :student-id="formData?.id" />
  183 + </Tabs.TabPane>
  184 + </Tabs>
  185 + </Modal>
  186 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/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 +
  22 +
  23 +const loading = ref(true) // 列表的加载中
  24 +const list = ref<StudentApi.Student[]>([]) // 列表的数据
  25 +
  26 +const total = ref(0) // 列表的总页数
  27 +const queryParams = reactive({
  28 + pageNo: 1,
  29 + pageSize: 10,
  30 + name: undefined,
  31 + birthday: undefined,
  32 + birthday: undefined,
  33 + sex: undefined,
  34 + enabled: undefined,
  35 + createTime: undefined,
  36 +})
  37 +const queryFormRef = ref() // 搜索的表单
  38 +const exportLoading = ref(false) // 导出的加载中
  39 +
  40 +/** 查询列表 */
  41 +async function getList() {
  42 + loading.value = true
  43 + try {
  44 + const params = cloneDeep(queryParams) as any;
  45 + if (params.birthday && Array.isArray(params.birthday)) {
  46 + params.birthday = (params.birthday as string[]).join(',');
  47 + }
  48 + if (params.createTime && Array.isArray(params.createTime)) {
  49 + params.createTime = (params.createTime as string[]).join(',');
  50 + }
  51 + const data = await getStudentPage(params)
  52 + list.value = data.list
  53 + total.value = data.total
  54 + } finally {
  55 + loading.value = false
  56 + }
  57 +}
  58 +
  59 +/** 搜索按钮操作 */
  60 +function handleQuery() {
  61 + queryParams.pageNo = 1
  62 + getList()
  63 +}
  64 +
  65 +/** 重置按钮操作 */
  66 +function resetQuery() {
  67 + queryFormRef.value.resetFields()
  68 + handleQuery()
  69 +}
  70 +
  71 +const [FormModal, formModalApi] = useVbenModal({
  72 + connectedComponent: StudentForm,
  73 + destroyOnClose: true,
  74 +});
  75 +
  76 +/** 创建学生 */
  77 +function handleCreate() {
  78 + formModalApi.setData(null).open();
  79 +}
  80 +
  81 +/** 编辑学生 */
  82 +function handleEdit(row: StudentApi.Student) {
  83 + formModalApi.setData(row).open();
  84 +}
  85 +
  86 +
  87 +/** 删除学生 */
  88 +async function handleDelete(row: StudentApi.Student) {
  89 + const hideLoading = message.loading({
  90 + content: $t('ui.actionMessage.deleting', [row.id]),
  91 + duration: 0,
  92 + });
  93 + try {
  94 + await deleteStudent(row.id!);
  95 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  96 + await getList();
  97 + } finally {
  98 + hideLoading();
  99 + }
  100 +}
  101 +
  102 +/** 批量删除学生 */
  103 +async function handleDeleteBatch() {
  104 + const hideLoading = message.loading({
  105 + content: $t('ui.actionMessage.deleting'),
  106 + duration: 0,
  107 + });
  108 + try {
  109 + await deleteStudentList(checkedIds.value);
  110 + checkedIds.value = [];
  111 + message.success($t('ui.actionMessage.deleteSuccess'));
  112 + await getList();
  113 + } finally {
  114 + hideLoading();
  115 + }
  116 +}
  117 +
  118 +const checkedIds = ref<number[]>([])
  119 +function handleRowCheckboxChange({
  120 + records,
  121 +}: {
  122 + records: StudentApi.Student[];
  123 +}) {
  124 + checkedIds.value = records.map((item) => item.id!);
  125 +}
  126 +
  127 +/** 导出表格 */
  128 +async function handleExport() {
  129 +try {
  130 + exportLoading.value = true;
  131 + const data = await exportStudent(queryParams);
  132 + downloadFileFromBlobPart({ fileName: '学生.xls', source: data });
  133 +}finally {
  134 + exportLoading.value = false;
  135 +}
  136 +}
  137 +
  138 +
  139 +
  140 +/** 初始化 */
  141 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  142 +onMounted(() => {
  143 + getList();
  144 +});
  145 +</script>
  146 +
  147 +<template>
  148 + <Page auto-content-height>
  149 + <FormModal @success="getList" />
  150 +
  151 + <Card v-if="!hiddenSearchBar" class="mb-4">
  152 + <!-- 搜索工作栏 -->
  153 + <Form
  154 + :model="queryParams"
  155 + ref="queryFormRef"
  156 + layout="inline"
  157 + >
  158 + <Form.Item label="名字" name="name">
  159 + <Input
  160 + v-model:value="queryParams.name"
  161 + placeholder="请输入名字"
  162 + allowClear
  163 + @pressEnter="handleQuery"
  164 + class="w-full"
  165 + />
  166 + </Form.Item>
  167 + <Form.Item label="出生日期" name="birthday">
  168 + <DatePicker
  169 + v-model:value="queryParams.birthday"
  170 + valueFormat="YYYY-MM-DD"
  171 + placeholder="选择出生日期"
  172 + allowClear
  173 + class="w-full"
  174 + />
  175 + </Form.Item>
  176 + <Form.Item label="性别" name="sex">
  177 + <Select
  178 + v-model:value="queryParams.sex"
  179 + placeholder="请选择性别"
  180 + allowClear
  181 + class="w-full"
  182 + >
  183 + <Select.Option
  184 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  185 + :key="dict.value"
  186 + :value="dict.value"
  187 + >
  188 + {{ dict.label }}
  189 + </Select.Option>
  190 + </Select>
  191 + </Form.Item>
  192 + <Form.Item label="是否有效" name="enabled">
  193 + <Select
  194 + v-model:value="queryParams.enabled"
  195 + placeholder="请选择是否有效"
  196 + allowClear
  197 + class="w-full"
  198 + >
  199 + <Select.Option
  200 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  201 + :key="dict.value"
  202 + :value="dict.value"
  203 + >
  204 + {{ dict.label }}
  205 + </Select.Option>
  206 + </Select>
  207 + </Form.Item>
  208 + <Form.Item label="创建时间" name="createTime">
  209 + <RangePicker
  210 + v-model:value="queryParams.createTime"
  211 + v-bind="getRangePickerDefaultProps()"
  212 + class="w-full"
  213 + />
  214 + </Form.Item>
  215 + <Form.Item>
  216 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  217 + <Button class="ml-2" @click="handleQuery" type="primary">
  218 + 搜索
  219 + </Button>
  220 + </Form.Item>
  221 + </Form>
  222 + </Card>
  223 +
  224 + <!-- 列表 -->
  225 + <Card title="学生">
  226 + <template #extra>
  227 + <VbenVxeTableToolbar
  228 + ref="tableToolbarRef"
  229 + v-model:hidden-search="hiddenSearchBar"
  230 + >
  231 + <Button
  232 + class="ml-2"
  233 + :icon="h(Plus)"
  234 + type="primary"
  235 + @click="handleCreate"
  236 + v-access:code="['infra:student:create']"
  237 + >
  238 + {{ $t('ui.actionTitle.create', ['学生']) }}
  239 + </Button>
  240 + <Button
  241 + :icon="h(Download)"
  242 + type="primary"
  243 + class="ml-2"
  244 + :loading="exportLoading"
  245 + @click="handleExport"
  246 + v-access:code="['infra:student:export']"
  247 + >
  248 + {{ $t('ui.actionTitle.export') }}
  249 + </Button>
  250 + <Button
  251 + :icon="h(Trash2)"
  252 + type="primary"
  253 + danger
  254 + class="ml-2"
  255 + :disabled="isEmpty(checkedIds)"
  256 + @click="handleDeleteBatch"
  257 + v-access:code="['infra:student:delete']"
  258 + >
  259 + 批量删除
  260 + </Button>
  261 + </VbenVxeTableToolbar>
  262 + </template>
  263 + <VxeTable
  264 + ref="tableRef"
  265 + :data="list"
  266 + show-overflow
  267 + :loading="loading"
  268 + @checkboxAll="handleRowCheckboxChange"
  269 + @checkboxChange="handleRowCheckboxChange"
  270 + >
  271 + <VxeColumn type="checkbox" width="40" />
  272 + <VxeColumn field="id" title="编号" align="center" />
  273 + <VxeColumn field="name" title="名字" align="center" />
  274 + <VxeColumn field="description" title="简介" align="center" />
  275 + <VxeColumn field="birthday" title="出生日期" align="center">
  276 + <template #default="{row}">
  277 + {{formatDateTime(row.birthday)}}
  278 + </template>
  279 + </VxeColumn>
  280 + <VxeColumn field="sex" title="性别" align="center">
  281 + <template #default="{row}">
  282 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  283 + </template>
  284 + </VxeColumn>
  285 + <VxeColumn field="enabled" title="是否有效" align="center">
  286 + <template #default="{row}">
  287 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  288 + </template>
  289 + </VxeColumn>
  290 + <VxeColumn field="avatar" title="头像" align="center" />
  291 + <VxeColumn field="video" title="附件" align="center" />
  292 + <VxeColumn field="memo" title="备注" align="center" />
  293 + <VxeColumn field="createTime" title="创建时间" align="center">
  294 + <template #default="{row}">
  295 + {{formatDateTime(row.createTime)}}
  296 + </template>
  297 + </VxeColumn>
  298 + <VxeColumn field="operation" title="操作" align="center">
  299 + <template #default="{row}">
  300 + <Button
  301 + size="small"
  302 + type="link"
  303 + @click="handleEdit(row)"
  304 + v-access:code="['infra:student:update']"
  305 + >
  306 + {{ $t('ui.actionTitle.edit') }}
  307 + </Button>
  308 + <Button
  309 + size="small"
  310 + type="link"
  311 + danger
  312 + class="ml-2"
  313 + @click="handleDelete(row)"
  314 + v-access:code="['infra:student:delete']"
  315 + >
  316 + {{ $t('ui.actionTitle.delete') }}
  317 + </Button>
  318 + </template>
  319 + </VxeColumn>
  320 + </VxeTable>
  321 + <!-- 分页 -->
  322 + <div class="mt-2 flex justify-end">
  323 + <Pagination
  324 + :total="total"
  325 + v-model:current="queryParams.pageNo"
  326 + v-model:page-size="queryParams.pageSize"
  327 + show-size-changer
  328 + @change="getList"
  329 + />
  330 + </div>
  331 + </Card>
  332 + </Page>
  333 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/vue/student-contact-form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +
  4 +import { computed, ref, h, onMounted, watch, nextTick } from 'vue';
  5 +
  6 +import { DICT_TYPE } from '@vben/constants';
  7 +import { getDictOptions } from '@vben/hooks';
  8 +
  9 +import { message, Tabs, Form, Input, Textarea, Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'ant-design-vue';
  10 +import { $t } from '#/locales';
  11 +
  12 + import type { VxeTableInstance } from '#/adapter/vxe-table';
  13 +import { Plus } from "@vben/icons";
  14 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  15 +import { ImageUpload, FileUpload } from "#/components/upload";
  16 +import { getStudentContactListByStudentId } from '#/api/infra/demo';
  17 +
  18 +const props = defineProps<{
  19 + studentId?: number // 学生编号(主表的关联字段)
  20 +}>()
  21 +
  22 + const list = ref<StudentApi.StudentContact[]>([]) // 列表的数据
  23 +const tableRef = ref<VxeTableInstance>();
  24 +
  25 +/** 添加学生联系人 */
  26 +async function handleAdd() {
  27 + await tableRef.value?.insertAt({} as StudentApi.StudentContact, -1);
  28 +}
  29 +
  30 +/** 删除学生联系人 */
  31 +async function handleDelete(row: StudentApi.StudentContact) {
  32 + await tableRef.value?.remove(row);
  33 +}
  34 +
  35 +/** 提供获取表格数据的方法供父组件调用 */
  36 +defineExpose({
  37 + getData: (): StudentApi.StudentContact[] => {
  38 + const data = list.value as StudentApi.StudentContact[];
  39 + const removeRecords = tableRef.value?.getRemoveRecords() as StudentApi.StudentContact[];
  40 + const insertRecords = tableRef.value?.getInsertRecords() as StudentApi.StudentContact[];
  41 + return [
  42 + ...data.filter(
  43 + (row) => !removeRecords.some((removed) => removed.id === row.id),
  44 + ),
  45 + ...insertRecords.map((row: any) => ({ ...row, id: undefined })),
  46 + ];
  47 + },
  48 +});
  49 +
  50 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  51 +watch(
  52 + () => props.studentId,
  53 + async (val) => {
  54 + if (!val) {
  55 + return;
  56 + }
  57 + list.value = await getStudentContactListByStudentId(props.studentId!);
  58 + },
  59 + { immediate: true },
  60 +);
  61 +</script>
  62 +
  63 +<template>
  64 + <VxeTable ref="tableRef" :data="list" show-overflow class="mx-4">
  65 + <VxeColumn field="name" title="名字" align="center">
  66 + <template #default="{ row }">
  67 + <Input v-model:value="row.name" />
  68 + </template>
  69 + </VxeColumn>
  70 + <VxeColumn field="description" title="简介" align="center">
  71 + <template #default="{ row }">
  72 + <Textarea v-model:value="row.description" />
  73 + </template>
  74 + </VxeColumn>
  75 + <VxeColumn field="birthday" title="出生日期" align="center">
  76 + <template #default="{ row }">
  77 + <DatePicker
  78 + v-model:value="row.birthday"
  79 + :showTime="true"
  80 + format="YYYY-MM-DD HH:mm:ss"
  81 + valueFormat='x'
  82 + />
  83 + </template>
  84 + </VxeColumn>
  85 + <VxeColumn field="sex" title="性别" align="center">
  86 + <template #default="{ row }">
  87 + <Select v-model:value="row.sex" placeholder="请选择性别">
  88 + <Select.Option
  89 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')"
  90 + :key="dict.value"
  91 + :value="dict.value"
  92 + >
  93 + {{ dict.label }}
  94 + </Select.Option>
  95 + </Select>
  96 + </template>
  97 + </VxeColumn>
  98 + <VxeColumn field="enabled" title="是否有效" align="center">
  99 + <template #default="{ row }">
  100 + <RadioGroup v-model:value="row.enabled">
  101 + <Radio
  102 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'boolean')"
  103 + :key="dict.value"
  104 + :value="dict.value"
  105 + >
  106 + {{ dict.label }}
  107 + </Radio>
  108 + </RadioGroup>
  109 + </template>
  110 + </VxeColumn>
  111 + <VxeColumn field="avatar" title="头像" align="center">
  112 + <template #default="{ row }">
  113 + <ImageUpload v-model:value="row.avatar" />
  114 + </template>
  115 + </VxeColumn>
  116 + <VxeColumn field="video" title="附件" align="center">
  117 + <template #default="{ row }">
  118 + <FileUpload v-model:value="row.video" />
  119 + </template>
  120 + </VxeColumn>
  121 + <VxeColumn field="memo" title="备注" align="center">
  122 + <template #default="{ row }">
  123 + <Textarea v-model:value="row.memo" />
  124 + </template>
  125 + </VxeColumn>
  126 + <VxeColumn field="operation" title="操作" align="center">
  127 + <template #default="{ row }">
  128 + <Button
  129 + size="small"
  130 + type="link"
  131 + danger
  132 + @click="handleDelete(row)"
  133 + v-access:code="['infra:student:delete']"
  134 + >
  135 + {{ $t('ui.actionTitle.delete') }}
  136 + </Button>
  137 + </template>
  138 + </VxeColumn>
  139 + </VxeTable>
  140 + <div class="flex justify-center mt-4">
  141 + <Button :icon="h(Plus)" type="primary" ghost @click="handleAdd" v-access:code="['infra:student:create']">
  142 + {{ $t('ui.actionTitle.create', ['学生联系人']) }}
  143 + </Button>
  144 + </div>
  145 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/vue/student-teacher-form 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { StudentApi } from '#/api/infra/demo';
  3 +
  4 +import { computed, ref, h, onMounted, watch, nextTick } from 'vue';
  5 +
  6 +import { DICT_TYPE } from '@vben/constants';
  7 +import { getDictOptions } from '@vben/hooks';
  8 +
  9 +import { message, Tabs, Form, Input, Textarea, Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'ant-design-vue';
  10 +import { $t } from '#/locales';
  11 +
  12 +import type { Rule } from 'ant-design-vue/es/form';
  13 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  14 +import { ImageUpload, FileUpload } from "#/components/upload";
  15 +import { getStudentTeacherByStudentId } from '#/api/infra/demo';
  16 +
  17 +const props = defineProps<{
  18 + studentId?: number // 学生编号(主表的关联字段)
  19 +}>()
  20 +
  21 +const formRef = ref();
  22 +const formData = ref<Partial<StudentApi.StudentTeacher>>({
  23 + id: undefined,
  24 + studentId: undefined,
  25 + name: undefined,
  26 + description: undefined,
  27 + birthday: undefined,
  28 + sex: undefined,
  29 + enabled: undefined,
  30 + avatar: undefined,
  31 + video: undefined,
  32 + memo: undefined,
  33 +});
  34 +const rules: Record<string, Rule[]> = {
  35 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  36 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  37 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  38 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  39 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  40 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  41 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  42 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }],
  43 +};
  44 +/** 暴露出表单校验方法和表单值获取方法 */
  45 +defineExpose({
  46 + validate: async () => await formRef.value?.validate(),
  47 + getValues: ()=> formData.value,
  48 +});
  49 +
  50 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  51 +watch(
  52 + () => props.studentId,
  53 + async (val) => {
  54 + if (!val) {
  55 + return;
  56 + }
  57 + await nextTick();
  58 + formData.value = await getStudentTeacherByStudentId(props.studentId!);
  59 + },
  60 + { immediate: true },
  61 +);
  62 +</script>
  63 +
  64 +<template>
  65 + <Form
  66 + ref="formRef"
  67 + class="mx-4"
  68 + :model="formData"
  69 + :rules="rules"
  70 + :label-col="{ span: 5 }"
  71 + :wrapper-col="{ span: 18 }"
  72 + >
  73 + <Form.Item label="名字" name="name">
  74 + <Input v-model:value="formData.name" placeholder="请输入名字" />
  75 + </Form.Item>
  76 + <Form.Item label="简介" name="description">
  77 + <Textarea v-model:value="formData.description" placeholder="请输入简介" />
  78 + </Form.Item>
  79 + <Form.Item label="出生日期" name="birthday">
  80 + <DatePicker
  81 + v-model:value="formData.birthday"
  82 + valueFormat="x"
  83 + placeholder="选择出生日期"
  84 + />
  85 + </Form.Item>
  86 + <Form.Item label="性别" name="sex">
  87 + <Select v-model:value="formData.sex" placeholder="请选择性别">
  88 + <Select.Option
  89 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  90 + :key="dict.value"
  91 + :value="dict.value"
  92 + >
  93 + {{ dict.label }}
  94 + </Select.Option>
  95 + </Select>
  96 + </Form.Item>
  97 + <Form.Item label="是否有效" name="enabled">
  98 + <RadioGroup v-model:value="formData.enabled">
  99 + <Radio
  100 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  101 + :key="dict.value"
  102 + :value="dict.value"
  103 + >
  104 + {{ dict.label }}
  105 + </Radio>
  106 + </RadioGroup>
  107 + </Form.Item>
  108 + <Form.Item label="头像" name="avatar">
  109 + <ImageUpload v-model:value="formData.avatar" />
  110 + </Form.Item>
  111 + <Form.Item label="附件" name="video">
  112 + <FileUpload v-model:value="formData.video" />
  113 + </Form.Item>
  114 + <Form.Item label="备注" name="memo">
  115 + <RichTextarea v-model="formData.memo" height="500px" />
  116 + </Form.Item>
  117 + </Form>
  118 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/xml/InfraStudentMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/xml/InfraStudentMapper
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/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/InfraStudentController",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentDO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentMapper",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  19 +}, {
  20 + "contentPath" : "xml/InfraStudentMapper",
  21 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentServiceImpl",
  24 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  25 +}, {
  26 + "contentPath" : "java/InfraStudentService",
  27 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentServiceImplTest",
  30 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  31 +}, {
  32 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  33 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  34 +}, {
  35 + "contentPath" : "sql/sql",
  36 + "filePath" : "sql/sql.sql"
  37 +}, {
  38 + "contentPath" : "sql/h2",
  39 + "filePath" : "sql/h2.sql"
  40 +}, {
  41 + "contentPath" : "vue/index",
  42 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  43 +}, {
  44 + "contentPath" : "vue/form",
  45 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  46 +}, {
  47 + "contentPath" : "ts/index",
  48 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  49 +} ]
0 50 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/ErrorCodeConstants_手动操作 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/ErrorCodeConstants_手动操作
1   -// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
2   -// ========== 学生 TODO 补充编号 ==========
3   -ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
4 1 \ No newline at end of file
  2 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  3 +// ========== 学生 TODO 补充编号 ==========
  4 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
5 5 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentController renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentController
1 1 package cn.iocoder.yudao.module.infra.controller.admin.demo;
2 2  
3 3 import org.springframework.web.bind.annotation.*;
4   -import javax.annotation.Resource;
  4 +import jakarta.annotation.Resource;
5 5 import org.springframework.validation.annotation.Validated;
6 6 import org.springframework.security.access.prepost.PreAuthorize;
7 7 import io.swagger.v3.oas.annotations.tags.Tag;
8 8 import io.swagger.v3.oas.annotations.Parameter;
9 9 import io.swagger.v3.oas.annotations.Operation;
10 10  
11   -import javax.validation.constraints.*;
12   -import javax.validation.*;
13   -import javax.servlet.http.*;
  11 +import jakarta.validation.constraints.*;
  12 +import jakarta.validation.*;
  13 +import jakarta.servlet.http.*;
14 14 import java.util.*;
15 15 import java.io.IOException;
16 16  
... ... @@ -22,8 +22,8 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 22  
23 23 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
24 24  
25   -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
26   -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  25 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  26 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
27 27  
28 28 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
29 29 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
... ... @@ -62,6 +62,15 @@ public class InfraStudentController {
62 62 return success(true);
63 63 }
64 64  
  65 + @DeleteMapping("/delete-list")
  66 + @Parameter(name = "ids", description = "编号", required = true)
  67 + @Operation(summary = "批量删除学生")
  68 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  69 + public CommonResult<Boolean> deleteStudentList(@RequestParam("ids") List<Long> ids) {
  70 + studentService.deleteStudentListByIds(ids);
  71 + return success(true);
  72 + }
  73 +
65 74 @GetMapping("/get")
66 75 @Operation(summary = "获得学生")
67 76 @Parameter(name = "id", description = "编号", required = true, example = "1024")
... ... @@ -82,7 +91,7 @@ public class InfraStudentController {
82 91 @GetMapping("/export-excel")
83 92 @Operation(summary = "导出学生 Excel")
84 93 @PreAuthorize("@ss.hasPermission('infra:student:export')")
85   - @OperateLog(type = EXPORT)
  94 + @ApiAccessLog(operateType = EXPORT)
86 95 public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
87 96 HttpServletResponse response) throws IOException {
88 97 pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentDO
... ... @@ -64,4 +64,5 @@ public class InfraStudentDO extends BaseDO {
64 64 */
65 65 private String memo;
66 66  
  67 +
67 68 }
68 69 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentMapper
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentPageReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentPageReqVO
... ... @@ -11,8 +11,6 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
11 11  
12 12 @Schema(description = "管理后台 - 学生分页 Request VO")
13 13 @Data
14   -@EqualsAndHashCode(callSuper = true)
15   -@ToString(callSuper = true)
16 14 public class InfraStudentPageReqVO extends PageParam {
17 15  
18 16 @Schema(description = "名字", example = "芋头")
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentRespVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentRespVO
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import java.util.*;
7 6 import org.springframework.format.annotation.DateTimeFormat;
8 7 import java.time.LocalDateTime;
9 8 import cn.idev.excel.annotation.*;
... ... @@ -57,4 +56,4 @@ public class InfraStudentRespVO {
57 56 @ExcelProperty("创建时间")
58 57 private LocalDateTime createTime;
59 58  
60 59 -}
  60 +}
61 61 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentSaveReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentSaveReqVO
... ... @@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import javax.validation.constraints.*;
7   -import java.util.*;
  6 +import jakarta.validation.constraints.*;
8 7 import org.springframework.format.annotation.DateTimeFormat;
9 8 import java.time.LocalDateTime;
10 9  
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentService renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentService
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
3 3 import java.util.*;
4   -import javax.validation.*;
  4 +import jakarta.validation.*;
5 5 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
6 6 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
... ... @@ -37,6 +37,13 @@ public interface InfraStudentService {
37 37 void deleteStudent(Long id);
38 38  
39 39 /**
  40 + * 批量删除学生
  41 + *
  42 + * @param ids 编号
  43 + */
  44 + void deleteStudentListByIds(List<Long> ids);
  45 +
  46 + /**
40 47 * 获得学生
41 48 *
42 49 * @param id 编号
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImpl renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentServiceImpl
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import org.springframework.stereotype.Service;
4   -import javax.annotation.Resource;
  5 +import jakarta.annotation.Resource;
5 6 import org.springframework.validation.annotation.Validated;
6 7 import org.springframework.transaction.annotation.Transactional;
7 8  
... ... @@ -15,6 +16,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
15 16 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
16 17  
17 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
18 21 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
19 22  
20 23 /**
... ... @@ -34,6 +37,7 @@ public class InfraStudentServiceImpl implements InfraStudentService {
34 37 // 插入
35 38 InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
36 39 studentMapper.insert(student);
  40 +
37 41 // 返回
38 42 return student.getId();
39 43 }
... ... @@ -55,6 +59,13 @@ public class InfraStudentServiceImpl implements InfraStudentService {
55 59 studentMapper.deleteById(id);
56 60 }
57 61  
  62 + @Override
  63 + public void deleteStudentListByIds(List<Long> ids) {
  64 + // 删除
  65 + studentMapper.deleteByIds(ids);
  66 + }
  67 +
  68 +
58 69 private void validateStudentExists(Long id) {
59 70 if (studentMapper.selectById(id) == null) {
60 71 throw exception(STUDENT_NOT_EXISTS);
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImplTest renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/java/InfraStudentServiceImplTest
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.infra.service.demo;
3 3 import org.junit.jupiter.api.Disabled;
4 4 import org.junit.jupiter.api.Test;
5 5  
6   -import javax.annotation.Resource;
  6 +import jakarta.annotation.Resource;
7 7  
8 8 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
9 9  
... ... @@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
12 12 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
13 13 import cn.iocoder.yudao.framework.common.pojo.PageResult;
14 14  
15   -import javax.annotation.Resource;
  15 +import jakarta.annotation.Resource;
16 16 import org.springframework.context.annotation.Import;
17 17 import java.util.*;
18 18 import java.time.LocalDateTime;
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/sql/h2 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/sql/h2
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/sql/sql renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/sql/sql
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   --- 暂时只支持 MySQL。如果你是 Oracle、PostgreSQL、SQLServer 的话,需要手动修改 @parentId 的部分的代码
13   -SELECT @parentId := LAST_INSERT_ID();
14   -
15   --- 按钮 SQL
16   -INSERT INTO system_menu(
17   - name, permission, type, sort, parent_id,
18   - path, icon, component, status
19   -)
20   -VALUES (
21   - '学生查询', 'infra:student:query', 3, 1, @parentId,
22   - '', '', '', 0
23   -);
24   -INSERT INTO system_menu(
25   - name, permission, type, sort, parent_id,
26   - path, icon, component, status
27   -)
28   -VALUES (
29   - '学生创建', 'infra:student:create', 3, 2, @parentId,
30   - '', '', '', 0
31   -);
32   -INSERT INTO system_menu(
33   - name, permission, type, sort, parent_id,
34   - path, icon, component, status
35   -)
36   -VALUES (
37   - '学生更新', 'infra:student:update', 3, 3, @parentId,
38   - '', '', '', 0
39   -);
40   -INSERT INTO system_menu(
41   - name, permission, type, sort, parent_id,
42   - path, icon, component, status
43   -)
44   -VALUES (
45   - '学生删除', 'infra:student:delete', 3, 4, @parentId,
46   - '', '', '', 0
47   -);
48   -INSERT INTO system_menu(
49   - name, permission, type, sort, parent_id,
50   - path, icon, component, status
51   -)
52   -VALUES (
53   - '学生导出', 'infra:student:export', 3, 5, @parentId,
54   - '', '', '', 0
55   -);
56 1 \ No newline at end of file
  2 +-- 菜单 SQL
  3 +INSERT INTO system_menu(
  4 + name, permission, type, sort, parent_id,
  5 + path, icon, component, status, component_name
  6 +)
  7 +VALUES (
  8 + '学生管理', '', 2, 0, 888,
  9 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  10 +);
  11 +
  12 +-- 按钮父菜单ID
  13 +SELECT @parentId := LAST_INSERT_ID();
  14 +
  15 +-- 按钮 SQL
  16 +INSERT INTO system_menu(
  17 + name, permission, type, sort, parent_id,
  18 + path, icon, component, status
  19 +)
  20 +VALUES (
  21 + '学生查询', 'infra:student:query', 3, 1, @parentId,
  22 + '', '', '', 0
  23 +);
  24 +INSERT INTO system_menu(
  25 + name, permission, type, sort, parent_id,
  26 + path, icon, component, status
  27 +)
  28 +VALUES (
  29 + '学生创建', 'infra:student:create', 3, 2, @parentId,
  30 + '', '', '', 0
  31 +);
  32 +INSERT INTO system_menu(
  33 + name, permission, type, sort, parent_id,
  34 + path, icon, component, status
  35 +)
  36 +VALUES (
  37 + '学生更新', 'infra:student:update', 3, 3, @parentId,
  38 + '', '', '', 0
  39 +);
  40 +INSERT INTO system_menu(
  41 + name, permission, type, sort, parent_id,
  42 + path, icon, component, status
  43 +)
  44 +VALUES (
  45 + '学生删除', 'infra:student:delete', 3, 4, @parentId,
  46 + '', '', '', 0
  47 +);
  48 +INSERT INTO system_menu(
  49 + name, permission, type, sort, parent_id,
  50 + path, icon, component, status
  51 +)
  52 +VALUES (
  53 + '学生导出', 'infra:student:export', 3, 5, @parentId,
  54 + '', '', '', 0
  55 +);
57 56 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/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 +}
0 55 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/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/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 +
  22 +
  23 +const loading = ref(true) // 列表的加载中
  24 +const list = ref<StudentApi.Student[]>([]) // 列表的数据
  25 +
  26 +const total = ref(0) // 列表的总页数
  27 +const queryParams = reactive({
  28 + pageNo: 1,
  29 + pageSize: 10,
  30 + name: undefined,
  31 + birthday: undefined,
  32 + birthday: undefined,
  33 + sex: undefined,
  34 + enabled: undefined,
  35 + createTime: undefined,
  36 +})
  37 +const queryFormRef = ref() // 搜索的表单
  38 +const exportLoading = ref(false) // 导出的加载中
  39 +
  40 +/** 查询列表 */
  41 +async function getList() {
  42 + loading.value = true
  43 + try {
  44 + const params = cloneDeep(queryParams) as any;
  45 + if (params.birthday && Array.isArray(params.birthday)) {
  46 + params.birthday = (params.birthday as string[]).join(',');
  47 + }
  48 + if (params.createTime && Array.isArray(params.createTime)) {
  49 + params.createTime = (params.createTime as string[]).join(',');
  50 + }
  51 + const data = await getStudentPage(params)
  52 + list.value = data.list
  53 + total.value = data.total
  54 + } finally {
  55 + loading.value = false
  56 + }
  57 +}
  58 +
  59 +/** 搜索按钮操作 */
  60 +function handleQuery() {
  61 + queryParams.pageNo = 1
  62 + getList()
  63 +}
  64 +
  65 +/** 重置按钮操作 */
  66 +function resetQuery() {
  67 + queryFormRef.value.resetFields()
  68 + handleQuery()
  69 +}
  70 +
  71 +const [FormModal, formModalApi] = useVbenModal({
  72 + connectedComponent: StudentForm,
  73 + destroyOnClose: true,
  74 +});
  75 +
  76 +/** 创建学生 */
  77 +function handleCreate() {
  78 + formModalApi.setData(null).open();
  79 +}
  80 +
  81 +/** 编辑学生 */
  82 +function handleEdit(row: StudentApi.Student) {
  83 + formModalApi.setData(row).open();
  84 +}
  85 +
  86 +
  87 +/** 删除学生 */
  88 +async function handleDelete(row: StudentApi.Student) {
  89 + const hideLoading = message.loading({
  90 + content: $t('ui.actionMessage.deleting', [row.id]),
  91 + duration: 0,
  92 + });
  93 + try {
  94 + await deleteStudent(row.id!);
  95 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  96 + await getList();
  97 + } finally {
  98 + hideLoading();
  99 + }
  100 +}
  101 +
  102 +/** 批量删除学生 */
  103 +async function handleDeleteBatch() {
  104 + const hideLoading = message.loading({
  105 + content: $t('ui.actionMessage.deleting'),
  106 + duration: 0,
  107 + });
  108 + try {
  109 + await deleteStudentList(checkedIds.value);
  110 + checkedIds.value = [];
  111 + message.success($t('ui.actionMessage.deleteSuccess'));
  112 + await getList();
  113 + } finally {
  114 + hideLoading();
  115 + }
  116 +}
  117 +
  118 +const checkedIds = ref<number[]>([])
  119 +function handleRowCheckboxChange({
  120 + records,
  121 +}: {
  122 + records: StudentApi.Student[];
  123 +}) {
  124 + checkedIds.value = records.map((item) => item.id!);
  125 +}
  126 +
  127 +/** 导出表格 */
  128 +async function handleExport() {
  129 +try {
  130 + exportLoading.value = true;
  131 + const data = await exportStudent(queryParams);
  132 + downloadFileFromBlobPart({ fileName: '学生.xls', source: data });
  133 +}finally {
  134 + exportLoading.value = false;
  135 +}
  136 +}
  137 +
  138 +
  139 +
  140 +/** 初始化 */
  141 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  142 +onMounted(() => {
  143 + getList();
  144 +});
  145 +</script>
  146 +
  147 +<template>
  148 + <Page auto-content-height>
  149 + <FormModal @success="getList" />
  150 +
  151 + <Card v-if="!hiddenSearchBar" class="mb-4">
  152 + <!-- 搜索工作栏 -->
  153 + <Form
  154 + :model="queryParams"
  155 + ref="queryFormRef"
  156 + layout="inline"
  157 + >
  158 + <Form.Item label="名字" name="name">
  159 + <Input
  160 + v-model:value="queryParams.name"
  161 + placeholder="请输入名字"
  162 + allowClear
  163 + @pressEnter="handleQuery"
  164 + class="w-full"
  165 + />
  166 + </Form.Item>
  167 + <Form.Item label="出生日期" name="birthday">
  168 + <DatePicker
  169 + v-model:value="queryParams.birthday"
  170 + valueFormat="YYYY-MM-DD"
  171 + placeholder="选择出生日期"
  172 + allowClear
  173 + class="w-full"
  174 + />
  175 + </Form.Item>
  176 + <Form.Item label="性别" name="sex">
  177 + <Select
  178 + v-model:value="queryParams.sex"
  179 + placeholder="请选择性别"
  180 + allowClear
  181 + class="w-full"
  182 + >
  183 + <Select.Option
  184 + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')"
  185 + :key="dict.value"
  186 + :value="dict.value"
  187 + >
  188 + {{ dict.label }}
  189 + </Select.Option>
  190 + </Select>
  191 + </Form.Item>
  192 + <Form.Item label="是否有效" name="enabled">
  193 + <Select
  194 + v-model:value="queryParams.enabled"
  195 + placeholder="请选择是否有效"
  196 + allowClear
  197 + class="w-full"
  198 + >
  199 + <Select.Option
  200 + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')"
  201 + :key="dict.value"
  202 + :value="dict.value"
  203 + >
  204 + {{ dict.label }}
  205 + </Select.Option>
  206 + </Select>
  207 + </Form.Item>
  208 + <Form.Item label="创建时间" name="createTime">
  209 + <RangePicker
  210 + v-model:value="queryParams.createTime"
  211 + v-bind="getRangePickerDefaultProps()"
  212 + class="w-full"
  213 + />
  214 + </Form.Item>
  215 + <Form.Item>
  216 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  217 + <Button class="ml-2" @click="handleQuery" type="primary">
  218 + 搜索
  219 + </Button>
  220 + </Form.Item>
  221 + </Form>
  222 + </Card>
  223 +
  224 + <!-- 列表 -->
  225 + <Card title="学生">
  226 + <template #extra>
  227 + <VbenVxeTableToolbar
  228 + ref="tableToolbarRef"
  229 + v-model:hidden-search="hiddenSearchBar"
  230 + >
  231 + <Button
  232 + class="ml-2"
  233 + :icon="h(Plus)"
  234 + type="primary"
  235 + @click="handleCreate"
  236 + v-access:code="['infra:student:create']"
  237 + >
  238 + {{ $t('ui.actionTitle.create', ['学生']) }}
  239 + </Button>
  240 + <Button
  241 + :icon="h(Download)"
  242 + type="primary"
  243 + class="ml-2"
  244 + :loading="exportLoading"
  245 + @click="handleExport"
  246 + v-access:code="['infra:student:export']"
  247 + >
  248 + {{ $t('ui.actionTitle.export') }}
  249 + </Button>
  250 + <Button
  251 + :icon="h(Trash2)"
  252 + type="primary"
  253 + danger
  254 + class="ml-2"
  255 + :disabled="isEmpty(checkedIds)"
  256 + @click="handleDeleteBatch"
  257 + v-access:code="['infra:student:delete']"
  258 + >
  259 + 批量删除
  260 + </Button>
  261 + </VbenVxeTableToolbar>
  262 + </template>
  263 + <VxeTable
  264 + ref="tableRef"
  265 + :data="list"
  266 + show-overflow
  267 + :loading="loading"
  268 + @checkboxAll="handleRowCheckboxChange"
  269 + @checkboxChange="handleRowCheckboxChange"
  270 + >
  271 + <VxeColumn type="checkbox" width="40" />
  272 + <VxeColumn field="id" title="编号" align="center" />
  273 + <VxeColumn field="name" title="名字" align="center" />
  274 + <VxeColumn field="description" title="简介" align="center" />
  275 + <VxeColumn field="birthday" title="出生日期" align="center">
  276 + <template #default="{row}">
  277 + {{formatDateTime(row.birthday)}}
  278 + </template>
  279 + </VxeColumn>
  280 + <VxeColumn field="sex" title="性别" align="center">
  281 + <template #default="{row}">
  282 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" />
  283 + </template>
  284 + </VxeColumn>
  285 + <VxeColumn field="enabled" title="是否有效" align="center">
  286 + <template #default="{row}">
  287 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" />
  288 + </template>
  289 + </VxeColumn>
  290 + <VxeColumn field="avatar" title="头像" align="center" />
  291 + <VxeColumn field="video" title="附件" align="center" />
  292 + <VxeColumn field="memo" title="备注" align="center" />
  293 + <VxeColumn field="createTime" title="创建时间" align="center">
  294 + <template #default="{row}">
  295 + {{formatDateTime(row.createTime)}}
  296 + </template>
  297 + </VxeColumn>
  298 + <VxeColumn field="operation" title="操作" align="center">
  299 + <template #default="{row}">
  300 + <Button
  301 + size="small"
  302 + type="link"
  303 + @click="handleEdit(row)"
  304 + v-access:code="['infra:student:update']"
  305 + >
  306 + {{ $t('ui.actionTitle.edit') }}
  307 + </Button>
  308 + <Button
  309 + size="small"
  310 + type="link"
  311 + danger
  312 + class="ml-2"
  313 + @click="handleDelete(row)"
  314 + v-access:code="['infra:student:delete']"
  315 + >
  316 + {{ $t('ui.actionTitle.delete') }}
  317 + </Button>
  318 + </template>
  319 + </VxeColumn>
  320 + </VxeTable>
  321 + <!-- 分页 -->
  322 + <div class="mt-2 flex justify-end">
  323 + <Pagination
  324 + :total="total"
  325 + v-model:current="queryParams.pageNo"
  326 + v-model:page-size="queryParams.pageSize"
  327 + show-size-changer
  328 + @change="getList"
  329 + />
  330 + </div>
  331 + </Card>
  332 + </Page>
  333 +</template>
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/xml/InfraStudentMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/xml/InfraStudentMapper
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraCategoryListReqVO",
  3 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategoryListReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraCategoryRespVO",
  6 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategoryRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraCategorySaveReqVO",
  9 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategorySaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraCategoryController",
  12 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraCategoryController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraCategoryDO",
  15 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraCategoryDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraCategoryMapper",
  18 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraCategoryMapper.java"
  19 +}, {
  20 + "contentPath" : "xml/InfraCategoryMapper",
  21 + "filePath" : "yudao-module-infra/src/main/resources/mapper/demo/InfraCategoryMapper.xml"
  22 +}, {
  23 + "contentPath" : "java/InfraCategoryServiceImpl",
  24 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryServiceImpl.java"
  25 +}, {
  26 + "contentPath" : "java/InfraCategoryService",
  27 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryService.java"
  28 +}, {
  29 + "contentPath" : "java/InfraCategoryServiceImplTest",
  30 + "filePath" : "yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryServiceImplTest.java"
  31 +}, {
  32 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  33 + "filePath" : "yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants_手动操作.java"
  34 +}, {
  35 + "contentPath" : "sql/sql",
  36 + "filePath" : "sql/sql.sql"
  37 +}, {
  38 + "contentPath" : "sql/h2",
  39 + "filePath" : "sql/h2.sql"
  40 +}, {
  41 + "contentPath" : "vue/index",
  42 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/index.vue"
  43 +}, {
  44 + "contentPath" : "vue/form",
  45 + "filePath" : "yudao-ui-admin-vben/src/views/infra/demo/modules/form.vue"
  46 +}, {
  47 + "contentPath" : "ts/index",
  48 + "filePath" : "yudao-ui-admin-vben/src/api/infra/demo/index.ts"
  49 +} ]
0 50 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/ErrorCodeConstants_手动操作 renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/ErrorCodeConstants_手动操作
1   -// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
2   -// ========== 分类 TODO 补充编号 ==========
3   -ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(TODO 补充编号, "分类不存在");
4   -ErrorCode CATEGORY_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子分类,无法删除");
5   -ErrorCode CATEGORY_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级分类不存在");
6   -ErrorCode CATEGORY_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父分类");
7   -ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该名字的分类");
8   -ErrorCode CATEGORY_PARENT_IS_CHILD = new ErrorCode(TODO 补充编号, "不能设置自己的子InfraCategory为父InfraCategory");
9 1 \ No newline at end of file
  2 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  3 +// ========== 分类 TODO 补充编号 ==========
  4 +ErrorCode CATEGORY_NOT_EXISTS = new ErrorCode(TODO 补充编号, "分类不存在");
  5 +ErrorCode CATEGORY_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子分类,无法删除");
  6 +ErrorCode CATEGORY_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级分类不存在");
  7 +ErrorCode CATEGORY_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父分类");
  8 +ErrorCode CATEGORY_NAME_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该名字的分类");
  9 +ErrorCode CATEGORY_PARENT_IS_CHILD = new ErrorCode(TODO 补充编号, "不能设置自己的子InfraCategory为父InfraCategory");
10 10 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryController renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/InfraCategoryController
1 1 package cn.iocoder.yudao.module.infra.controller.admin.demo;
2 2  
3 3 import org.springframework.web.bind.annotation.*;
4   -import javax.annotation.Resource;
  4 +import jakarta.annotation.Resource;
5 5 import org.springframework.validation.annotation.Validated;
6 6 import org.springframework.security.access.prepost.PreAuthorize;
7 7 import io.swagger.v3.oas.annotations.tags.Tag;
8 8 import io.swagger.v3.oas.annotations.Parameter;
9 9 import io.swagger.v3.oas.annotations.Operation;
10 10  
11   -import javax.validation.constraints.*;
12   -import javax.validation.*;
13   -import javax.servlet.http.*;
  11 +import jakarta.validation.constraints.*;
  12 +import jakarta.validation.*;
  13 +import jakarta.servlet.http.*;
14 14 import java.util.*;
15 15 import java.io.IOException;
16 16  
... ... @@ -22,8 +22,8 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
22 22  
23 23 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
24 24  
25   -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
26   -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  25 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  26 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
27 27  
28 28 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
29 29 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO;
... ... @@ -62,6 +62,7 @@ public class InfraCategoryController {
62 62 return success(true);
63 63 }
64 64  
  65 +
65 66 @GetMapping("/get")
66 67 @Operation(summary = "获得分类")
67 68 @Parameter(name = "id", description = "编号", required = true, example = "1024")
... ... @@ -82,7 +83,7 @@ public class InfraCategoryController {
82 83 @GetMapping("/export-excel")
83 84 @Operation(summary = "导出分类 Excel")
84 85 @PreAuthorize("@ss.hasPermission('infra:category:export')")
85   - @OperateLog(type = EXPORT)
  86 + @ApiAccessLog(operateType = EXPORT)
86 87 public void exportCategoryExcel(@Valid InfraCategoryListReqVO listReqVO,
87 88 HttpServletResponse response) throws IOException {
88 89 List<InfraCategoryDO> list = categoryService.getCategoryList(listReqVO);
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryDO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/InfraCategoryDO
... ... @@ -36,4 +36,5 @@ public class InfraCategoryDO extends BaseDO {
36 36 */
37 37 private Long parentId;
38 38  
  39 +
39 40 }
40 41 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryListReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/InfraCategoryListReqVO
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryMapper renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/InfraCategoryMapper
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryRespVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/InfraCategoryRespVO
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import java.util.*;
7 6 import cn.idev.excel.annotation.*;
8 7  
9 8 @Schema(description = "管理后台 - 分类 Response VO")
... ... @@ -23,4 +22,4 @@ public class InfraCategoryRespVO {
23 22 @ExcelProperty("父编号")
24 23 private Long parentId;
25 24  
26 25 -}
  26 +}
27 27 \ No newline at end of file
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategorySaveReqVO renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/InfraCategorySaveReqVO
... ... @@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
5 5 import java.util.*;
6   -import javax.validation.constraints.*;
7   -import java.util.*;
  6 +import jakarta.validation.constraints.*;
8 7  
9 8 @Schema(description = "管理后台 - 分类新增/修改 Request VO")
10 9 @Data
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryService renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/InfraCategoryService
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
3 3 import java.util.*;
4   -import javax.validation.*;
  4 +import jakarta.validation.*;
5 5 import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
6 6 import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO;
7 7 import cn.iocoder.yudao.framework.common.pojo.PageResult;
... ... @@ -36,6 +36,7 @@ public interface InfraCategoryService {
36 36 */
37 37 void deleteCategory(Long id);
38 38  
  39 +
39 40 /**
40 41 * 获得分类
41 42 *
... ...
yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryServiceImpl renamed to yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/java/InfraCategoryServiceImpl
1 1 package cn.iocoder.yudao.module.infra.service.demo;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import org.springframework.stereotype.Service;
4   -import javax.annotation.Resource;
  5 +import jakarta.annotation.Resource;
5 6 import org.springframework.validation.annotation.Validated;
6 7 import org.springframework.transaction.annotation.Transactional;
7 8  
... ... @@ -15,6 +16,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
15 16 import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraCategoryMapper;
16 17  
17 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  20 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
18 21 import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
19 22  
20 23 /**
... ... @@ -39,6 +42,7 @@ public class InfraCategoryServiceImpl implements InfraCategoryService {
39 42 // 插入
40 43 InfraCategoryDO category = BeanUtils.toBean(createReqVO, InfraCategoryDO.class);
41 44 categoryMapper.insert(category);
  45 +
42 46 // 返回
43 47 return category.getId();
44 48 }
... ... @@ -69,6 +73,7 @@ public class InfraCategoryServiceImpl implements InfraCategoryService {
69 73 categoryMapper.deleteById(id);
70 74 }
71 75  
  76 +
72 77 private void validateCategoryExists(Long id) {
73 78 if (categoryMapper.selectById(id) == null) {
74 79 throw exception(CATEGORY_NOT_EXISTS);
... ...