Commit 29ff41809133b138e4c08b080ffbd60b41c40c6d

Authored by 芋道源码
Committed by Gitee
2 parents e8bc284d 7ac74b44

!736 新增主子表、树表的代码生成

Merge pull request !736 from 芋道源码/feature/sub-table
Showing 236 changed files with 13585 additions and 1647 deletions
sql/mysql/ruoyi-vue-pro.sql
... ... @@ -11,7 +11,7 @@
11 11 Target Server Version : 80034
12 12 File Encoding : 65001
13 13  
14   - Date: 04/11/2023 20:42:49
  14 + Date: 18/11/2023 17:48:18
15 15 */
16 16  
17 17 SET NAMES utf8mb4;
... ... @@ -385,7 +385,7 @@ CREATE TABLE `infra_api_error_log` (
385 385 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
386 386 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
387 387 PRIMARY KEY (`id`) USING BTREE
388   -) ENGINE = InnoDB AUTO_INCREMENT = 1781 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
  388 +) ENGINE = InnoDB AUTO_INCREMENT = 1964 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统异常日志';
389 389  
390 390 -- ----------------------------
391 391 -- Records of infra_api_error_log
... ... @@ -423,7 +423,7 @@ CREATE TABLE `infra_codegen_column` (
423 423 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
424 424 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
425 425 PRIMARY KEY (`id`) USING BTREE
426   -) ENGINE = InnoDB AUTO_INCREMENT = 1804 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
  426 +) ENGINE = InnoDB AUTO_INCREMENT = 1905 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表字段定义';
427 427  
428 428 -- ----------------------------
429 429 -- Records of infra_codegen_column
... ... @@ -450,13 +450,18 @@ CREATE TABLE `infra_codegen_table` (
450 450 `template_type` tinyint NOT NULL DEFAULT 1 COMMENT '模板类型',
451 451 `front_type` tinyint NOT NULL COMMENT '前端类型',
452 452 `parent_menu_id` bigint NULL DEFAULT NULL COMMENT '父菜单编号',
  453 + `master_table_id` bigint NULL DEFAULT NULL COMMENT '主表的编号',
  454 + `sub_join_column_id` bigint NULL DEFAULT NULL COMMENT '子表关联主表的字段编号',
  455 + `sub_join_many` bit(1) NULL DEFAULT NULL COMMENT '主表与子表是否一对多',
  456 + `tree_parent_column_id` bigint NULL DEFAULT NULL COMMENT '树表的父字段编号',
  457 + `tree_name_column_id` bigint NULL DEFAULT NULL COMMENT '树表的名字字段编号',
453 458 `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
454 459 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
455 460 `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
456 461 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
457 462 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
458 463 PRIMARY KEY (`id`) USING BTREE
459   -) ENGINE = InnoDB AUTO_INCREMENT = 136 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义';
  464 +) ENGINE = InnoDB AUTO_INCREMENT = 146 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '代码生成表定义';
460 465  
461 466 -- ----------------------------
462 467 -- Records of infra_codegen_table
... ... @@ -522,6 +527,150 @@ BEGIN;
522 527 COMMIT;
523 528  
524 529 -- ----------------------------
  530 +-- Table structure for infra_demo01_contact
  531 +-- ----------------------------
  532 +DROP TABLE IF EXISTS `infra_demo01_contact`;
  533 +CREATE TABLE `infra_demo01_contact` (
  534 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  535 + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  536 + `sex` tinyint(1) NOT NULL COMMENT '性别',
  537 + `birthday` datetime NOT NULL COMMENT '出生年',
  538 + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '简介',
  539 + `avatar` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '头像',
  540 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  541 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  542 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  543 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  544 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  545 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  546 + PRIMARY KEY (`id`) USING BTREE
  547 +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '示例联系人表';
  548 +
  549 +-- ----------------------------
  550 +-- Records of infra_demo01_contact
  551 +-- ----------------------------
  552 +BEGIN;
  553 +INSERT INTO `infra_demo01_contact` (`id`, `name`, `sex`, `birthday`, `description`, `avatar`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '土豆', 2, '2023-11-07 00:00:00', '<p>天蚕土豆!呀</p>', 'http://127.0.0.1:48080/admin-api/infra/file/4/get/46f8fa1a37db3f3960d8910ff2fe3962ab3b2db87cf2f8ccb4dc8145b8bdf237.jpeg', '1', '2023-11-15 23:34:30', '1', '2023-11-15 23:47:39', b'0', 1);
  554 +COMMIT;
  555 +
  556 +-- ----------------------------
  557 +-- Table structure for infra_demo02_category
  558 +-- ----------------------------
  559 +DROP TABLE IF EXISTS `infra_demo02_category`;
  560 +CREATE TABLE `infra_demo02_category` (
  561 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  562 + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  563 + `parent_id` bigint NOT NULL COMMENT '父级编号',
  564 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  565 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  566 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  567 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  568 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  569 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  570 + PRIMARY KEY (`id`) USING BTREE
  571 +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '示例分类表';
  572 +
  573 +-- ----------------------------
  574 +-- Records of infra_demo02_category
  575 +-- ----------------------------
  576 +BEGIN;
  577 +INSERT INTO `infra_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '土豆', 0, '1', '2023-11-15 23:34:30', '1', '2023-11-16 20:24:23', b'0', 1);
  578 +INSERT INTO `infra_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '番茄', 0, '1', '2023-11-16 20:24:00', '1', '2023-11-16 20:24:15', b'0', 1);
  579 +INSERT INTO `infra_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, '怪怪', 0, '1', '2023-11-16 20:24:32', '1', '2023-11-16 20:24:32', b'0', 1);
  580 +INSERT INTO `infra_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, '小番茄', 2, '1', '2023-11-16 20:24:39', '1', '2023-11-16 20:24:39', b'0', 1);
  581 +INSERT INTO `infra_demo02_category` (`id`, `name`, `parent_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '大番茄', 2, '1', '2023-11-16 20:24:46', '1', '2023-11-16 20:24:46', b'0', 1);
  582 +COMMIT;
  583 +
  584 +-- ----------------------------
  585 +-- Table structure for infra_demo03_course
  586 +-- ----------------------------
  587 +DROP TABLE IF EXISTS `infra_demo03_course`;
  588 +CREATE TABLE `infra_demo03_course` (
  589 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  590 + `student_id` bigint NOT NULL COMMENT '学生编号',
  591 + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  592 + `score` tinyint NOT NULL COMMENT '分数',
  593 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  594 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  595 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  596 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  597 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  598 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  599 + PRIMARY KEY (`id`) USING BTREE
  600 +) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生课程表';
  601 +
  602 +-- ----------------------------
  603 +-- Records of infra_demo03_course
  604 +-- ----------------------------
  605 +BEGIN;
  606 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 2, '语文', 66, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1);
  607 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (3, 2, '数学', 22, '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1);
  608 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (6, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', b'1', 1);
  609 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:44:40', b'1', 1);
  610 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', b'1', 1);
  611 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 15:47:09', b'1', 1);
  612 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (10, 5, '体育', 23, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1);
  613 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (11, 5, '计算机', 11, '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1);
  614 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (12, 2, '电脑', 33, '1', '2023-11-17 00:20:42', '1', '2023-11-16 16:20:45', b'1', 1);
  615 +INSERT INTO `infra_demo03_course` (`id`, `student_id`, `name`, `score`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (13, 9, '滑雪', 12, '1', '2023-11-17 13:13:20', '1', '2023-11-17 13:13:20', b'0', 1);
  616 +COMMIT;
  617 +
  618 +-- ----------------------------
  619 +-- Table structure for infra_demo03_grade
  620 +-- ----------------------------
  621 +DROP TABLE IF EXISTS `infra_demo03_grade`;
  622 +CREATE TABLE `infra_demo03_grade` (
  623 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  624 + `student_id` bigint NOT NULL COMMENT '学生编号',
  625 + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  626 + `teacher` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '班主任',
  627 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  628 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  629 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  630 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  631 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  632 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  633 + PRIMARY KEY (`id`) USING BTREE
  634 +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生班级表';
  635 +
  636 +-- ----------------------------
  637 +-- Records of infra_demo03_grade
  638 +-- ----------------------------
  639 +BEGIN;
  640 +INSERT INTO `infra_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (7, 2, '三年 2 班', '周杰伦', '1', '2023-11-16 23:21:49', '1', '2023-11-16 23:21:49', b'0', 1);
  641 +INSERT INTO `infra_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (8, 5, '华为', '遥遥领先', '1', '2023-11-16 23:22:46', '1', '2023-11-16 23:47:10', b'0', 1);
  642 +INSERT INTO `infra_demo03_grade` (`id`, `student_id`, `name`, `teacher`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, 9, '小图', '小娃111', '1', '2023-11-17 13:10:23', '1', '2023-11-17 13:10:23', b'0', 1);
  643 +COMMIT;
  644 +
  645 +-- ----------------------------
  646 +-- Table structure for infra_demo03_student
  647 +-- ----------------------------
  648 +DROP TABLE IF EXISTS `infra_demo03_student`;
  649 +CREATE TABLE `infra_demo03_student` (
  650 + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  651 + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
  652 + `sex` tinyint NOT NULL COMMENT '性别',
  653 + `birthday` datetime NOT NULL COMMENT '出生日期',
  654 + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '简介',
  655 + `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
  656 + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  657 + `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
  658 + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  659 + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
  660 + `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
  661 + PRIMARY KEY (`id`) USING BTREE
  662 +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '学生表';
  663 +
  664 +-- ----------------------------
  665 +-- Records of infra_demo03_student
  666 +-- ----------------------------
  667 +BEGIN;
  668 +INSERT INTO `infra_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '小白', 1, '2023-11-16 00:00:00', '<p>厉害</p>', '1', '2023-11-16 23:21:49', '1', '2023-11-17 16:49:06', b'0', 1);
  669 +INSERT INTO `infra_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (5, '大黑', 2, '2023-11-13 00:00:00', '<p>你在教我做事?</p>', '1', '2023-11-16 23:22:46', '1', '2023-11-17 16:49:07', b'0', 1);
  670 +INSERT INTO `infra_demo03_student` (`id`, `name`, `sex`, `birthday`, `description`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (9, '小花', 1, '2023-11-07 00:00:00', '<p>哈哈哈</p>', '1', '2023-11-17 00:04:47', '1', '2023-11-17 16:49:08', b'0', 1);
  671 +COMMIT;
  672 +
  673 +-- ----------------------------
525 674 -- Table structure for infra_file
526 675 -- ----------------------------
527 676 DROP TABLE IF EXISTS `infra_file`;
... ... @@ -539,7 +688,7 @@ CREATE TABLE `infra_file` (
539 688 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
540 689 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
541 690 PRIMARY KEY (`id`) USING BTREE
542   -) ENGINE = InnoDB AUTO_INCREMENT = 1108 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
  691 +) ENGINE = InnoDB AUTO_INCREMENT = 1128 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
543 692  
544 693 -- ----------------------------
545 694 -- Records of infra_file
... ... @@ -588,7 +737,7 @@ CREATE TABLE `infra_file_content` (
588 737 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
589 738 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
590 739 PRIMARY KEY (`id`) USING BTREE
591   -) ENGINE = InnoDB AUTO_INCREMENT = 202 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
  740 +) ENGINE = InnoDB AUTO_INCREMENT = 221 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '文件表';
592 741  
593 742 -- ----------------------------
594 743 -- Records of infra_file_content
... ... @@ -666,31 +815,6 @@ BEGIN;
666 815 COMMIT;
667 816  
668 817 -- ----------------------------
669   --- Table structure for infra_test_demo
670   --- ----------------------------
671   -DROP TABLE IF EXISTS `infra_test_demo`;
672   -CREATE TABLE `infra_test_demo` (
673   - `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
674   - `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '名字',
675   - `status` tinyint NOT NULL DEFAULT 0 COMMENT '状态',
676   - `type` tinyint NOT NULL COMMENT '类型',
677   - `category` tinyint NOT NULL COMMENT '分类',
678   - `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '备注',
679   - `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
680   - `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
681   - `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
682   - `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
683   - `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
684   - PRIMARY KEY (`id`) USING BTREE
685   -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
686   -
687   --- ----------------------------
688   --- Records of infra_test_demo
689   --- ----------------------------
690   -BEGIN;
691   -COMMIT;
692   -
693   --- ----------------------------
694 818 -- Table structure for member_address
695 819 -- ----------------------------
696 820 DROP TABLE IF EXISTS `member_address`;
... ... @@ -1131,7 +1255,7 @@ CREATE TABLE `system_dept` (
1131 1255 -- Records of system_dept
1132 1256 -- ----------------------------
1133 1257 BEGIN;
1134   -INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-06-19 00:29:10', b'0', 1);
  1258 +INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, '芋道源码', 0, 0, 1, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2023-11-14 23:30:36', b'0', 1);
1135 1259 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (101, '深圳总公司', 100, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '1', '2022-05-16 20:25:23', b'0', 1);
1136 1260 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (102, '长沙分公司', 100, 2, NULL, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '', '2021-12-15 05:01:40', b'0', 1);
1137 1261 INSERT INTO `system_dept` (`id`, `name`, `parent_id`, `sort`, `leader_user_id`, `phone`, `email`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, '研发部门', 101, 1, 104, '15888888888', 'ry@qq.com', 0, 'admin', '2021-01-05 17:03:47', '103', '2022-01-14 01:04:14', b'0', 1);
... ... @@ -1165,14 +1289,14 @@ CREATE TABLE `system_dict_data` (
1165 1289 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1166 1290 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1167 1291 PRIMARY KEY (`id`) USING BTREE
1168   -) ENGINE = InnoDB AUTO_INCREMENT = 1435 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
  1292 +) ENGINE = InnoDB AUTO_INCREMENT = 1447 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表';
1169 1293  
1170 1294 -- ----------------------------
1171 1295 -- Records of system_dict_data
1172 1296 -- ----------------------------
1173 1297 BEGIN;
1174 1298 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, 1, '男', '1', 'system_user_sex', 0, 'default', 'A', '性别男', 'admin', '2021-01-05 17:03:48', '1', '2022-03-29 00:14:39', b'0');
1175   -INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 2, '女', '2', 'system_user_sex', 1, 'success', '', '性别女', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 01:30:51', b'0');
  1299 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2, 2, '女', '2', 'system_user_sex', 0, 'success', '', '性别女', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 23:30:37', b'0');
1176 1300 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (8, 1, '正常', '1', 'infra_job_status', 0, 'success', '', '正常状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:38', b'0');
1177 1301 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (9, 2, '暂停', '2', 'infra_job_status', 0, 'danger', '', '停用状态', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:33:45', b'0');
1178 1302 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (12, 1, '系统内置', '1', 'infra_config_type', 0, 'danger', '', '参数类型 - 系统内置', 'admin', '2021-01-05 17:03:48', '1', '2022-02-16 19:06:02', b'0');
... ... @@ -1474,6 +1598,12 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st
1474 1598 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1438, 31, '微信公众平台', '31', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:18', '1', '2023-11-04 13:05:18', b'0');
1475 1599 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1439, 32, '微信开放平台', '32', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:30', '1', '2023-11-04 13:05:30', b'0');
1476 1600 INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1440, 34, '微信小程序', '34', 'system_social_type', 0, '', '', '', '1', '2023-11-04 13:05:38', '1', '2023-11-04 13:07:16', b'0');
  1601 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1441, 1, '上架', '1', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:34', '1', '2023-10-30 21:49:34', b'0');
  1602 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1442, 0, '下架', '0', 'crm_product_status', 0, 'success', '', '', '1', '2023-10-30 21:49:13', '1', '2023-10-30 21:49:13', b'0');
  1603 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1443, 15, '子表', '15', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-13 23:06:16', '1', '2023-11-13 23:06:16', b'0');
  1604 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1444, 10, '主表(标准模式)', '10', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:32:49', '1', '2023-11-14 12:32:49', b'0');
  1605 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1445, 11, '主表(ERP 模式)', '11', 'infra_codegen_template_type', 0, 'default', '', '', '1', '2023-11-14 12:33:05', '1', '2023-11-14 12:33:05', b'0');
  1606 +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1446, 12, '主表(内嵌模式)', '12', 'infra_codegen_template_type', 0, '', '', '', '1', '2023-11-14 12:33:31', '1', '2023-11-14 12:33:31', b'0');
1477 1607 COMMIT;
1478 1608  
1479 1609 -- ----------------------------
... ... @@ -1494,7 +1624,7 @@ CREATE TABLE `system_dict_type` (
1494 1624 `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间',
1495 1625 PRIMARY KEY (`id`) USING BTREE,
1496 1626 UNIQUE INDEX `dict_type`(`type` ASC) USING BTREE
1497   -) ENGINE = InnoDB AUTO_INCREMENT = 600 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
  1627 +) ENGINE = InnoDB AUTO_INCREMENT = 605 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表';
1498 1628  
1499 1629 -- ----------------------------
1500 1630 -- Records of system_dict_type
... ... @@ -1573,6 +1703,7 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat
1573 1703 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (188, '客户来源', 'crm_customer_source', 0, 'CRM 客户来源', '1', '2023-10-28 23:00:34', '1', '2023-10-28 15:11:16', b'0', NULL);
1574 1704 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (600, 'Banner 位置', 'promotion_banner_position', 0, '', '1', '2023-10-08 07:24:25', '1', '2023-11-04 13:04:02', b'0', '1970-01-01 00:00:00');
1575 1705 INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (601, '社交类型', 'system_social_type', 0, '', '1', '2023-11-04 13:03:54', '1', '2023-11-04 13:03:54', b'0', '1970-01-01 00:00:00');
  1706 +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (604, '产品状态', 'crm_product_status', 0, '', '1', '2023-10-30 21:47:59', '1', '2023-10-30 21:48:45', b'0', '1970-01-01 00:00:00');
1576 1707 COMMIT;
1577 1708  
1578 1709 -- ----------------------------
... ... @@ -1621,7 +1752,7 @@ CREATE TABLE `system_login_log` (
1621 1752 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1622 1753 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
1623 1754 PRIMARY KEY (`id`) USING BTREE
1624   -) ENGINE = InnoDB AUTO_INCREMENT = 2631 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
  1755 +) ENGINE = InnoDB AUTO_INCREMENT = 2647 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '系统访问记录';
1625 1756  
1626 1757 -- ----------------------------
1627 1758 -- Records of system_login_log
... ... @@ -1751,7 +1882,7 @@ CREATE TABLE `system_menu` (
1751 1882 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
1752 1883 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
1753 1884 PRIMARY KEY (`id`) USING BTREE
1754   -) ENGINE = InnoDB AUTO_INCREMENT = 2449 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
  1885 +) ENGINE = InnoDB AUTO_INCREMENT = 2504 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '菜单权限表';
1755 1886  
1756 1887 -- ----------------------------
1757 1888 -- Records of system_menu
... ... @@ -1839,11 +1970,7 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
1839 1970 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1065, '设置用户角色', 'system:permission:assign-user-role', 3, 8, 101, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-07 10:23:28', '', '2022-04-20 17:03:10', b'0');
1840 1971 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1066, '获得 Redis 监控信息', 'infra:redis:get-monitor-info', 3, 1, 113, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-26 01:02:31', '', '2022-04-20 17:03:10', b'0');
1841 1972 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1067, '获得 Redis Key 列表', 'infra:redis:get-key-list', 3, 2, 113, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-01-26 01:02:52', '', '2022-04-20 17:03:10', b'0');
1842   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1070, '代码生成示例', 'infra:test-demo:query', 2, 1, 2, 'test-demo', 'validCode', 'infra/testDemo/index', NULL, 0, b'1', b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
1843   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1071, '测试示例表创建', 'infra:test-demo:create', 3, 1, 1070, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
1844   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1072, '测试示例表更新', 'infra:test-demo:update', 3, 2, 1070, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
1845   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1073, '测试示例表删除', 'infra:test-demo:delete', 3, 3, 1070, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
1846   -INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1074, '测试示例表导出', 'infra:test-demo:export', 3, 4, 1070, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-06 12:42:49', '1', '2022-04-20 17:03:10', b'0');
  1973 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1070, '代码生成案例', '', 1, 1, 2, 'demo', 'ep:aim', 'infra/testDemo/index', NULL, 0, b'1', b'1', b'1', '', '2021-02-06 12:42:49', '1', '2023-11-15 23:45:53', b'0');
1847 1974 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1075, '任务触发', 'infra:job:trigger', 3, 8, 110, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2021-02-07 13:03:10', '', '2022-04-20 17:03:10', b'0');
1848 1975 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1076, '数据库文档', '', 2, 4, 2, 'db-doc', 'table', 'infra/dbDoc/index', 'InfraDBDoc', 0, b'1', b'1', b'1', '', '2021-02-08 01:41:47', '1', '2023-04-08 09:13:38', b'0');
1849 1976 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1077, '监控平台', '', 2, 13, 2, 'skywalking', 'eye-open', 'infra/skywalking/index', 'InfraSkyWalking', 0, b'1', b'1', b'1', '', '2021-02-08 20:41:31', '1', '2023-04-08 10:39:06', b'0');
... ... @@ -2310,6 +2437,26 @@ INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_i
2310 2437 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2451, '三方应用更新', 'system:social-client:update', 3, 3, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:44:27', '1', '2023-11-04 12:44:27', b'0');
2311 2438 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2452, '三方应用删除', 'system:social-client:delete', 3, 4, 2448, '', '', '', '', 0, b'1', b'1', b'1', '1', '2023-11-04 12:44:43', '1', '2023-11-04 12:44:43', b'0');
2312 2439 INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2453, '三方用户', 'system:social-user:query', 2, 2, 2447, 'user', 'ep:avatar', 'system/social/user/index.vue', 'SocialUser', 0, b'1', b'1', b'1', '1', '2023-11-04 14:01:05', '1', '2023-11-04 14:01:05', b'0');
  2440 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2472, '主子表(内嵌)', '', 2, 12, 1070, 'demo03-inner', 'fa:power-off', 'infra/demo/demo03/inner/index', 'Demo03StudentInner', 0, b'1', b'1', b'1', '', '2023-11-13 04:39:51', '1', '2023-11-16 23:53:46', b'0');
  2441 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2478, '单表(增删改查)', '', 2, 1, 1070, 'demo01-contact', 'ep:bicycle', 'infra/demo/demo01/index', 'Demo01Contact', 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '1', '2023-11-16 20:34:40', b'0');
  2442 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2479, '示例联系人查询', 'infra:demo01-contact:query', 3, 1, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0');
  2443 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2480, '示例联系人创建', 'infra:demo01-contact:create', 3, 2, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0');
  2444 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2481, '示例联系人更新', 'infra:demo01-contact:update', 3, 3, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0');
  2445 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2482, '示例联系人删除', 'infra:demo01-contact:delete', 3, 4, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0');
  2446 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2483, '示例联系人导出', 'infra:demo01-contact:export', 3, 5, 2478, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-15 14:42:30', '', '2023-11-15 14:42:30', b'0');
  2447 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2484, '树表(增删改查)', '', 2, 2, 1070, 'demo02-category', 'fa:tree', 'infra/demo/demo02/index', 'Demo02Category', 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '1', '2023-11-16 20:35:01', b'0');
  2448 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2485, '示例分类查询', 'infra:demo02-category:query', 3, 1, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0');
  2449 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2486, '示例分类创建', 'infra:demo02-category:create', 3, 2, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0');
  2450 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2487, '示例分类更新', 'infra:demo02-category:update', 3, 3, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0');
  2451 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2488, '示例分类删除', 'infra:demo02-category:delete', 3, 4, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0');
  2452 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2489, '示例分类导出', 'infra:demo02-category:export', 3, 5, 2484, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:18:27', '', '2023-11-16 12:18:27', b'0');
  2453 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2490, '主子表(标准)', '', 2, 10, 1070, 'demo03-normal', 'fa:battery-3', 'infra/demo/demo03/normal/index', 'Demo03StudentNormal', 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '1', '2023-11-16 23:10:03', b'0');
  2454 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2491, '学生查询', 'infra:demo03-student:query', 3, 1, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0');
  2455 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2492, '学生创建', 'infra:demo03-student:create', 3, 2, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0');
  2456 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2493, '学生更新', 'infra:demo03-student:update', 3, 3, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0');
  2457 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2494, '学生删除', 'infra:demo03-student:delete', 3, 4, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0');
  2458 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2495, '学生导出', 'infra:demo03-student:export', 3, 5, 2490, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-11-16 12:53:37', '', '2023-11-16 12:53:37', b'0');
  2459 +INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2497, '主子表(ERP)', '', 2, 11, 1070, 'demo03-erp', 'ep:calendar', 'infra/demo/demo03/erp/index', 'Demo03StudentERP', 0, b'1', b'1', b'1', '', '2023-11-16 15:50:59', '1', '2023-11-17 13:19:56', b'0');
2313 2460 COMMIT;
2314 2461  
2315 2462 -- ----------------------------
... ... @@ -2336,7 +2483,7 @@ CREATE TABLE `system_notice` (
2336 2483 -- ----------------------------
2337 2484 BEGIN;
2338 2485 INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, '芋道的公众', '<p>新版本内容133</p>', 1, 0, 'admin', '2021-01-05 17:03:48', '1', '2022-05-04 21:00:20', b'0', 1);
2339   -INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '维护通知:2018-07-01 若依系统凌晨维护', '<p><img src=\"http://test.yudao.iocoder.cn/b7cb3cf49b4b3258bf7309a09dd2f4e5.jpg\">维护内容</p>', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2022-05-11 12:34:24', b'0', 1);
  2486 +INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, '维护通知:2018-07-01 若依系统凌晨维护', '<p><img src=\"http://test.yudao.iocoder.cn/b7cb3cf49b4b3258bf7309a09dd2f4e5.jpg\" alt=\"\" data-href=\"\" style=\"\"/>1111</p>', 2, 1, 'admin', '2021-01-05 17:03:48', '1', '2023-11-11 12:51:11', b'0', 1);
2340 2487 INSERT INTO `system_notice` (`id`, `title`, `content`, `type`, `status`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, '我是测试标题', '<p>哈哈哈哈123</p>', 1, 0, '110', '2022-02-22 01:01:25', '110', '2022-02-22 01:01:46', b'0', 121);
2341 2488 COMMIT;
2342 2489  
... ... @@ -2430,7 +2577,7 @@ CREATE TABLE `system_oauth2_access_token` (
2430 2577 PRIMARY KEY (`id`) USING BTREE,
2431 2578 INDEX `idx_access_token`(`access_token` ASC) USING BTREE,
2432 2579 INDEX `idx_refresh_token`(`refresh_token` ASC) USING BTREE
2433   -) ENGINE = InnoDB AUTO_INCREMENT = 3152 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
  2580 +) ENGINE = InnoDB AUTO_INCREMENT = 3467 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 访问令牌';
2434 2581  
2435 2582 -- ----------------------------
2436 2583 -- Records of system_oauth2_access_token
... ... @@ -2552,7 +2699,7 @@ CREATE TABLE `system_oauth2_refresh_token` (
2552 2699 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2553 2700 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2554 2701 PRIMARY KEY (`id`) USING BTREE
2555   -) ENGINE = InnoDB AUTO_INCREMENT = 1099 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
  2702 +) ENGINE = InnoDB AUTO_INCREMENT = 1115 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = 'OAuth2 刷新令牌';
2556 2703  
2557 2704 -- ----------------------------
2558 2705 -- Records of system_oauth2_refresh_token
... ... @@ -2592,7 +2739,7 @@ CREATE TABLE `system_operate_log` (
2592 2739 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2593 2740 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2594 2741 PRIMARY KEY (`id`) USING BTREE
2595   -) ENGINE = InnoDB AUTO_INCREMENT = 8845 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
  2742 +) ENGINE = InnoDB AUTO_INCREMENT = 9090 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '操作日志记录';
2596 2743  
2597 2744 -- ----------------------------
2598 2745 -- Records of system_operate_log
... ... @@ -2618,15 +2765,15 @@ CREATE TABLE `system_post` (
2618 2765 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
2619 2766 `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
2620 2767 PRIMARY KEY (`id`) USING BTREE
2621   -) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '岗位信息表';
  2768 +) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '岗位信息表';
2622 2769  
2623 2770 -- ----------------------------
2624 2771 -- Records of system_post
2625 2772 -- ----------------------------
2626 2773 BEGIN;
2627 2774 INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'ceo', '董事长', 1, 0, '', 'admin', '2021-01-06 17:03:48', '1', '2023-02-11 15:19:04', b'0', 1);
2628   -INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 'se', '项目经理', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2021-12-12 10:47:47', b'0', 1);
2629   -INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 'user', '普通员工', 4, 0, '111', 'admin', '2021-01-05 17:03:48', '1', '2023-02-11 15:19:00', b'0', 1);
  2775 +INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2, 'se', '项目经理', 2, 0, '', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 09:18:20', b'0', 1);
  2776 +INSERT INTO `system_post` (`id`, `code`, `name`, `sort`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (4, 'user', '普通员工', 4, 0, '111', 'admin', '2021-01-05 17:03:48', '1', '2023-11-15 09:18:18', b'0', 1);
2630 2777 COMMIT;
2631 2778  
2632 2779 -- ----------------------------
... ... @@ -2819,10 +2966,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
2819 2966 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1657, 101, 1066, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2820 2967 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1658, 101, 1067, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2821 2968 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1659, 101, 1070, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2822   -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1660, 101, 1071, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2823   -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1661, 101, 1072, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2824   -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1662, 101, 1073, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2825   -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1663, 101, 1074, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2826 2969 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1664, 101, 1075, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2827 2970 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1665, 101, 1076, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
2828 2971 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1666, 101, 1077, '1', '2022-04-01 22:21:37', '1', '2022-04-01 22:21:37', b'0', 1);
... ... @@ -3140,10 +3283,6 @@ INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_t
3140 3283 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2027, 2, 1066, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3141 3284 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2028, 2, 1067, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3142 3285 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2029, 2, 1070, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3143   -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2030, 2, 1071, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3144   -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2031, 2, 1072, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3145   -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2032, 2, 1073, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3146   -INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2033, 2, 1074, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3147 3286 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2034, 2, 1075, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3148 3287 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2035, 2, 1076, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
3149 3288 INSERT INTO `system_role_menu` (`id`, `role_id`, `menu_id`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (2036, 2, 1082, '1', '2023-01-25 08:42:52', '1', '2023-01-25 08:42:52', b'0', 1);
... ... @@ -3643,7 +3782,7 @@ CREATE TABLE `system_sms_log` (
3643 3782 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
3644 3783 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3645 3784 PRIMARY KEY (`id`) USING BTREE
3646   -) ENGINE = InnoDB AUTO_INCREMENT = 503 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
  3785 +) ENGINE = InnoDB AUTO_INCREMENT = 502 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信日志';
3647 3786  
3648 3787 -- ----------------------------
3649 3788 -- Records of system_sms_log
... ... @@ -3673,7 +3812,7 @@ CREATE TABLE `system_sms_template` (
3673 3812 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
3674 3813 `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
3675 3814 PRIMARY KEY (`id`) USING BTREE
3676   -) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信模板';
  3815 +) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '短信模板';
3677 3816  
3678 3817 -- ----------------------------
3679 3818 -- Records of system_sms_template
... ... @@ -3803,9 +3942,9 @@ CREATE TABLE `system_tenant` (
3803 3942 -- Records of system_tenant
3804 3943 -- ----------------------------
3805 3944 BEGIN;
3806   -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'https://www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2022-02-23 12:15:11', b'0');
3807   -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'http://www.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-09-16 16:59:42', b'0');
3808   -INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'https://www.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-09-16 16:59:27', b'0');
  3945 +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1, '芋道源码', NULL, '芋艿', '17321315478', 0, 'www.iocoder.cn', 0, '2099-02-19 17:14:16', 9999, '1', '2021-01-05 17:03:47', '1', '2023-11-06 11:41:41', b'0');
  3946 +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (121, '小租户', 110, '小王2', '15601691300', 0, 'zsxq.iocoder.cn', 111, '2024-03-11 00:00:00', 20, '1', '2022-02-22 00:56:14', '1', '2023-11-06 11:41:47', b'0');
  3947 +INSERT INTO `system_tenant` (`id`, `name`, `contact_user_id`, `contact_name`, `contact_mobile`, `status`, `website`, `package_id`, `expire_time`, `account_count`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (122, '测试租户', 113, '芋道', '15601691300', 0, 'test.iocoder.cn', 111, '2022-04-30 00:00:00', 50, '1', '2022-03-07 21:37:58', '1', '2023-11-06 11:41:53', b'0');
3809 3948 COMMIT;
3810 3949  
3811 3950 -- ----------------------------
... ... @@ -3944,7 +4083,7 @@ CREATE TABLE `system_users` (
3944 4083 -- Records of system_users
3945 4084 -- ----------------------------
3946 4085 BEGIN;
3947   -INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://127.0.0.1:48080/admin-api/infra/file/4/get/37e56010ecbee472cdd821ac4b608e151e62a74d9633f15d085aee026eedeb60.png', 0, '0:0:0:0:0:0:0:1', '2023-11-04 10:33:16', 'admin', '2021-01-05 17:03:47', NULL, '2023-11-04 10:33:16', b'0', 1);
  4086 +INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (1, 'admin', '$2a$10$mRMIYLDtRHlf6.9ipiqH1.Z.bh/R9dO9d5iHiGYPigi6r5KOoR2Wm', '芋道源码', '管理员', 103, '[1]', 'aoteman@126.com', '15612345678', 1, 'http://127.0.0.1:48080/admin-api/infra/file/4/get/37e56010ecbee472cdd821ac4b608e151e62a74d9633f15d085aee026eedeb60.png', 0, '0:0:0:0:0:0:0:1', '2023-11-18 17:19:30', 'admin', '2021-01-05 17:03:47', NULL, '2023-11-18 17:19:30', b'0', 1);
3948 4087 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (100, 'yudao', '$2a$10$11U48RhyJ5pSBYWSn12AD./ld671.ycSzJHbyrtpeoMeYiw31eo8a', '芋道', '不要吓我', 104, '[1]', 'yudao@iocoder.cn', '15601691300', 1, '', 1, '127.0.0.1', '2022-07-09 23:03:33', '', '2021-01-07 09:07:17', NULL, '2022-07-09 23:03:33', b'0', 1);
3949 4088 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (103, 'yuanma', '$2a$10$YMpimV4T6BtDhIaA8jSW.u8UTGBeGhc/qwXP4oxoMr4mOw9.qttt6', '源码', NULL, 106, NULL, 'yuanma@iocoder.cn', '15601701300', 0, '', 0, '127.0.0.1', '2022-07-08 01:26:27', '', '2021-01-13 23:50:35', NULL, '2022-07-08 01:26:27', b'0', 1);
3950 4089 INSERT INTO `system_users` (`id`, `username`, `password`, `nickname`, `remark`, `dept_id`, `post_ids`, `email`, `mobile`, `sex`, `avatar`, `status`, `login_ip`, `login_date`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `tenant_id`) VALUES (104, 'test', '$2a$10$GP8zvqHB//TekuzYZSBYAuBQJiNq1.fxQVDYJ.uBCOnWCtDVKE4H6', '测试号', NULL, 107, '[1,2]', '111@qq.com', '15601691200', 1, '', 0, '0:0:0:0:0:0:0:1', '2023-09-24 18:21:19', '', '2021-01-21 02:13:53', NULL, '2023-09-24 18:21:19', b'0', 1);
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/pojo/PageParam.java
... ... @@ -15,6 +15,13 @@ public class PageParam implements Serializable {
15 15 private static final Integer PAGE_NO = 1;
16 16 private static final Integer PAGE_SIZE = 10;
17 17  
  18 + /**
  19 + * 每页条数 - 不分页
  20 + *
  21 + * 例如说,导出接口,可以设置 {@link #pageSize} 为 -1 不分页,查询所有数据。
  22 + */
  23 + public static final Integer PAGE_SIZE_NONE = -1;
  24 +
18 25 @Schema(description = "页码,从 1 开始", requiredMode = Schema.RequiredMode.REQUIRED,example = "1")
19 26 @NotNull(message = "页码不能为空")
20 27 @Min(value = 1, message = "页码最小值为 1")
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
... ... @@ -238,7 +238,7 @@ public class CollectionUtils {
238 238 if (CollUtil.isEmpty(from)) {
239 239 return null;
240 240 }
241   - assert from.size() > 0; // 断言,避免告警
  241 + assert !from.isEmpty(); // 断言,避免告警
242 242 T t = from.stream().max(Comparator.comparing(valueFunc)).get();
243 243 return valueFunc.apply(t);
244 244 }
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
... ... @@ -3,6 +3,7 @@ package cn.iocoder.yudao.framework.common.util.json;
3 3 import cn.hutool.core.util.ArrayUtil;
4 4 import cn.hutool.core.util.StrUtil;
5 5 import cn.hutool.json.JSONUtil;
  6 +import com.fasterxml.jackson.annotation.JsonInclude;
6 7 import com.fasterxml.jackson.core.type.TypeReference;
7 8 import com.fasterxml.jackson.databind.DeserializationFeature;
8 9 import com.fasterxml.jackson.databind.JsonNode;
... ... @@ -30,6 +31,7 @@ public class JsonUtils {
30 31 static {
31 32 objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
32 33 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  34 + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略 null 值
33 35 objectMapper.registerModules(new JavaTimeModule()); // 解决 LocalDateTime 的序列化
34 36 }
35 37  
... ... @@ -71,6 +73,20 @@ public class JsonUtils {
71 73 }
72 74 }
73 75  
  76 + public static <T> T parseObject(String text, String path, Class<T> clazz) {
  77 + if (StrUtil.isEmpty(text)) {
  78 + return null;
  79 + }
  80 + try {
  81 + JsonNode treeNode = objectMapper.readTree(text);
  82 + JsonNode pathNode = treeNode.path(path);
  83 + return objectMapper.readValue(pathNode.toString(), clazz);
  84 + } catch (IOException e) {
  85 + log.error("json parse err,json:{}", text, e);
  86 + throw new RuntimeException(e);
  87 + }
  88 + }
  89 +
74 90 public static <T> T parseObject(String text, Type type) {
75 91 if (StrUtil.isEmpty(text)) {
76 92 return null;
... ... @@ -132,6 +148,20 @@ public class JsonUtils {
132 148 }
133 149 }
134 150  
  151 + public static <T> List<T> parseArray(String text, String path, Class<T> clazz) {
  152 + if (StrUtil.isEmpty(text)) {
  153 + return null;
  154 + }
  155 + try {
  156 + JsonNode treeNode = objectMapper.readTree(text);
  157 + JsonNode pathNode = treeNode.path(path);
  158 + return objectMapper.readValue(pathNode.toString(), objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
  159 + } catch (IOException e) {
  160 + log.error("json parse err,json:{}", text, e);
  161 + throw new RuntimeException(e);
  162 + }
  163 + }
  164 +
135 165 public static JsonNode parseTree(String text) {
136 166 try {
137 167 return objectMapper.readTree(text);
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/BeanUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.common.util.object;
  2 +
  3 +import cn.hutool.core.bean.BeanUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * Bean 工具类
  11 + *
  12 + * 1. 默认使用 {@link cn.hutool.core.bean.BeanUtil} 作为实现类,虽然不同 bean 工具的性能有差别,但是对绝大多数同学的项目,不用在意这点性能
  13 + * 2. 针对复杂的对象转换,可以搜参考 AuthConvert 实现,通过 mapstruct + default 配合实现
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public class BeanUtils {
  18 +
  19 + public static <T> T toBean(Object source, Class<T> targetClass) {
  20 + return BeanUtil.toBean(source, targetClass);
  21 + }
  22 +
  23 + public static <S, T> List<T> toBean(List<S> source, Class<T> targetType) {
  24 + if (source == null) {
  25 + return null;
  26 + }
  27 + return CollectionUtils.convertList(source, s -> toBean(s, targetType));
  28 + }
  29 +
  30 + public static <S, T> PageResult<T> toBean(PageResult<S> source, Class<T> targetType) {
  31 + if (source == null) {
  32 + return null;
  33 + }
  34 + return new PageResult<>(toBean(source.getList(), targetType), source.getTotal());
  35 + }
  36 +
  37 +}
0 38 \ No newline at end of file
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java
... ... @@ -50,4 +50,20 @@ public class StrUtils {
50 50 return Arrays.stream(integers).boxed().collect(Collectors.toList());
51 51 }
52 52  
  53 + /**
  54 + * 移除字符串中,包含指定字符串的行
  55 + *
  56 + * @param content 字符串
  57 + * @param sequence 包含的字符串
  58 + * @return 移除后的字符串
  59 + */
  60 + public static String removeLineContains(String content, String sequence) {
  61 + if (StrUtil.isEmpty(content) || StrUtil.isEmpty(sequence)) {
  62 + return content;
  63 + }
  64 + return Arrays.stream(content.split("\n"))
  65 + .filter(line -> !line.contains(sequence))
  66 + .collect(Collectors.joining("\n"));
  67 + }
  68 +
53 69 }
... ...
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
... ... @@ -26,6 +26,12 @@ import java.util.List;
26 26 public interface BaseMapperX<T> extends MPJBaseMapper<T> {
27 27  
28 28 default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
  29 + // 特殊:不分页,直接查询全部
  30 + if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageNo())) {
  31 + List<T> list = selectList(queryWrapper);
  32 + return new PageResult<>(list, (long) list.size());
  33 + }
  34 +
29 35 // MyBatis Plus 查询
30 36 IPage<T> mpPage = MyBatisUtils.buildPage(pageParam);
31 37 selectPage(mpPage, queryWrapper);
... ... @@ -93,10 +99,15 @@ public interface BaseMapperX&lt;T&gt; extends MPJBaseMapper&lt;T&gt; {
93 99 return selectList(new LambdaQueryWrapper<T>().in(field, values));
94 100 }
95 101  
  102 + @Deprecated
96 103 default List<T> selectList(SFunction<T, ?> leField, SFunction<T, ?> geField, Object value) {
97 104 return selectList(new LambdaQueryWrapper<T>().le(leField, value).ge(geField, value));
98 105 }
99 106  
  107 + default List<T> selectList(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
  108 + return selectList(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
  109 + }
  110 +
100 111 /**
101 112 * 批量插入,适合大量数据插入
102 113 *
... ... @@ -128,8 +139,20 @@ public interface BaseMapperX&lt;T&gt; extends MPJBaseMapper&lt;T&gt; {
128 139 Db.updateBatchById(entities, size);
129 140 }
130 141  
131   - default void saveOrUpdateBatch(Collection<T> collection) {
  142 + default void insertOrUpdate(T entity) {
  143 + Db.saveOrUpdate(entity);
  144 + }
  145 +
  146 + default void insertOrUpdateBatch(Collection<T> collection) {
132 147 Db.saveOrUpdateBatch(collection);
133 148 }
134 149  
  150 + default int delete(String field, String value) {
  151 + return delete(new QueryWrapper<T>().eq(field, value));
  152 + }
  153 +
  154 + default int delete(SFunction<T, ?> field, Object value) {
  155 + return delete(new LambdaQueryWrapper<T>().eq(field, value));
  156 + }
  157 +
135 158 }
... ...
yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/enums/ErrorCodeConstants.java
... ... @@ -42,9 +42,10 @@ public interface ErrorCodeConstants {
42 42 ErrorCode CODEGEN_SYNC_NONE_CHANGE = new ErrorCode(1_003_001_007, "同步失败,不存在改变");
43 43 ErrorCode CODEGEN_TABLE_INFO_TABLE_COMMENT_IS_NULL = new ErrorCode(1_003_001_008, "数据库的表注释未填写");
44 44 ErrorCode CODEGEN_TABLE_INFO_COLUMN_COMMENT_IS_NULL = new ErrorCode(1_003_001_009, "数据库的表字段({})注释未填写");
45   -
46   - // ========== 字典类型(测试)1-001-005-000 ==========
47   - ErrorCode TEST_DEMO_NOT_EXISTS = new ErrorCode(1_001_005_000, "测试示例不存在");
  45 + ErrorCode CODEGEN_MASTER_TABLE_NOT_EXISTS = new ErrorCode(1_003_001_010, "主表(id={})定义不存在,请检查");
  46 + ErrorCode CODEGEN_SUB_COLUMN_NOT_EXISTS = new ErrorCode(1_003_001_011, "子表的字段(id={})不存在,请检查");
  47 + ErrorCode CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE = new ErrorCode(1_003_001_012, "主表生成代码失败,原因:它没有子表");
  48 + ErrorCode CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_COLUMN = new ErrorCode(1_003_001_013, "主表生成代码失败,原因:它的子表({})没有字段");
48 49  
49 50 // ========== 文件配置 1-001-006-000 ==========
50 51 ErrorCode FILE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_006_000, "文件配置不存在");
... ... @@ -54,4 +55,19 @@ public interface ErrorCodeConstants {
54 55 ErrorCode DATA_SOURCE_CONFIG_NOT_EXISTS = new ErrorCode(1_001_007_000, "数据源配置不存在");
55 56 ErrorCode DATA_SOURCE_CONFIG_NOT_OK = new ErrorCode(1_001_007_001, "数据源配置不正确,无法进行连接");
56 57  
  58 + // ========== 数据源配置 1-001-107-000 ==========
  59 + ErrorCode DEMO_STUDENT_NOT_EXISTS = new ErrorCode(1_001_107_000, "学生不存在");
  60 +
  61 + // ========== 学生 1-001-201-000 ==========
  62 + ErrorCode DEMO01_CONTACT_NOT_EXISTS = new ErrorCode(1_001_201_000, "示例联系人不存在");
  63 + ErrorCode DEMO02_CATEGORY_NOT_EXISTS = new ErrorCode(1_001_201_001, "示例分类不存在");
  64 + ErrorCode DEMO02_CATEGORY_EXITS_CHILDREN = new ErrorCode(1_001_201_002, "存在存在子示例分类,无法删除");
  65 + ErrorCode DEMO02_CATEGORY_PARENT_NOT_EXITS = new ErrorCode(1_001_201_003,"父级示例分类不存在");
  66 + ErrorCode DEMO02_CATEGORY_PARENT_ERROR = new ErrorCode(1_001_201_004, "不能设置自己为父示例分类");
  67 + ErrorCode DEMO02_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_001_201_005, "已经存在该名字的示例分类");
  68 + ErrorCode DEMO02_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_001_201_006, "不能设置自己的子示例分类为父示例分类");
  69 + ErrorCode DEMO03_STUDENT_NOT_EXISTS = new ErrorCode(1_001_201_007, "学生不存在");
  70 + ErrorCode DEMO03_GRADE_NOT_EXISTS = new ErrorCode(1_001_201_008, "学生班级不存在");
  71 + ErrorCode DEMO03_GRADE_EXISTS = new ErrorCode(1_001_201_009, "学生班级已存在");
  72 +
57 73 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/CodegenController.java
... ... @@ -60,10 +60,19 @@ public class CodegenController {
60 60 return success(codegenService.getDatabaseTableList(dataSourceConfigId, name, comment));
61 61 }
62 62  
  63 + @GetMapping("/table/list")
  64 + @Operation(summary = "获得表定义列表")
  65 + @Parameter(name = "dataSourceConfigId", description = "数据源配置的编号", required = true, example = "1")
  66 + @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
  67 + public CommonResult<List<CodegenTableRespVO>> getCodegenTableList(@RequestParam(value = "dataSourceConfigId") Long dataSourceConfigId) {
  68 + List<CodegenTableDO> list = codegenService.getCodegenTableList(dataSourceConfigId);
  69 + return success(CodegenConvert.INSTANCE.convertList05(list));
  70 + }
  71 +
63 72 @GetMapping("/table/page")
64 73 @Operation(summary = "获得表定义分页")
65 74 @PreAuthorize("@ss.hasPermission('infra:codegen:query')")
66   - public CommonResult<PageResult<CodegenTableRespVO>> getCodeGenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
  75 + public CommonResult<PageResult<CodegenTableRespVO>> getCodegenTablePage(@Valid CodegenTablePageReqVO pageReqVO) {
67 76 PageResult<CodegenTableDO> pageResult = codegenService.getCodegenTablePage(pageReqVO);
68 77 return success(CodegenConvert.INSTANCE.convertPage(pageResult));
69 78 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/CodegenUpdateReqVO.java
... ... @@ -4,6 +4,8 @@ import cn.hutool.core.util.ObjectUtil;
4 4 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.column.CodegenColumnBaseVO;
5 5 import cn.iocoder.yudao.module.infra.controller.admin.codegen.vo.table.CodegenTableBaseVO;
6 6 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  7 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
  8 +import com.fasterxml.jackson.annotation.JsonIgnore;
7 9 import io.swagger.v3.oas.annotations.media.Schema;
8 10 import lombok.Data;
9 11 import lombok.EqualsAndHashCode;
... ... @@ -37,12 +39,27 @@ public class CodegenUpdateReqVO {
37 39 private Long id;
38 40  
39 41 @AssertTrue(message = "上级菜单不能为空,请前往 [修改生成配置 -> 生成信息] 界面,设置“上级菜单”字段")
  42 + @JsonIgnore
40 43 public boolean isParentMenuIdValid() {
41 44 // 生成场景为管理后台时,必须设置上级菜单,不然生成的菜单 SQL 是无父级菜单的
42 45 return ObjectUtil.notEqual(getScene(), CodegenSceneEnum.ADMIN.getScene())
43 46 || getParentMenuId() != null;
44 47 }
45 48  
  49 + @AssertTrue(message = "关联的父表信息不全")
  50 + @JsonIgnore
  51 + public boolean isSubValid() {
  52 + return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.SUB)
  53 + || (ObjectUtil.isAllNotEmpty(getMasterTableId(), getSubJoinColumnId(), getSubJoinMany()));
  54 + }
  55 +
  56 + @AssertTrue(message = "关联的树表信息不全")
  57 + @JsonIgnore
  58 + public boolean isTreeValid() {
  59 + return ObjectUtil.notEqual(getTemplateType(), CodegenTemplateTypeEnum.TREE)
  60 + || (ObjectUtil.isAllNotEmpty(getTreeParentColumnId(), getTreeNameColumnId()));
  61 + }
  62 +
46 63 }
47 64  
48 65 @Schema(description = "更新表定义")
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/codegen/vo/table/CodegenTableBaseVO.java
... ... @@ -58,4 +58,16 @@ public class CodegenTableBaseVO {
58 58 @Schema(description = "父菜单编号", example = "1024")
59 59 private Long parentMenuId;
60 60  
  61 + @Schema(description = "主表的编号", example = "2048")
  62 + private Long masterTableId;
  63 + @Schema(description = "子表关联主表的字段编号", example = "4096")
  64 + private Long subJoinColumnId;
  65 + @Schema(description = "主表与子表是否一对多", example = "4096")
  66 + private Boolean subJoinMany;
  67 +
  68 + @Schema(description = "树表的父字段编号", example = "8192")
  69 + private Long treeParentColumnId;
  70 + @Schema(description = "树表的名字字段编号", example = "16384")
  71 + private Long treeNameColumnId;
  72 +
61 73 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/Demo01ContactController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  8 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactRespVO;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01.Demo01ContactDO;
  13 +import cn.iocoder.yudao.module.infra.service.demo.demo01.Demo01ContactService;
  14 +import io.swagger.v3.oas.annotations.Operation;
  15 +import io.swagger.v3.oas.annotations.Parameter;
  16 +import io.swagger.v3.oas.annotations.tags.Tag;
  17 +import org.springframework.security.access.prepost.PreAuthorize;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.*;
  20 +
  21 +import javax.annotation.Resource;
  22 +import javax.servlet.http.HttpServletResponse;
  23 +import javax.validation.Valid;
  24 +import java.io.IOException;
  25 +import java.util.List;
  26 +
  27 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  28 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
  29 +
  30 +@Tag(name = "管理后台 - 示例联系人")
  31 +@RestController
  32 +@RequestMapping("/infra/demo01-contact")
  33 +@Validated
  34 +public class Demo01ContactController {
  35 +
  36 + @Resource
  37 + private Demo01ContactService demo01ContactService;
  38 +
  39 + @PostMapping("/create")
  40 + @Operation(summary = "创建示例联系人")
  41 + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:create')")
  42 + public CommonResult<Long> createDemo01Contact(@Valid @RequestBody Demo01ContactSaveReqVO createReqVO) {
  43 + return success(demo01ContactService.createDemo01Contact(createReqVO));
  44 + }
  45 +
  46 + @PutMapping("/update")
  47 + @Operation(summary = "更新示例联系人")
  48 + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:update')")
  49 + public CommonResult<Boolean> updateDemo01Contact(@Valid @RequestBody Demo01ContactSaveReqVO updateReqVO) {
  50 + demo01ContactService.updateDemo01Contact(updateReqVO);
  51 + return success(true);
  52 + }
  53 +
  54 + @DeleteMapping("/delete")
  55 + @Operation(summary = "删除示例联系人")
  56 + @Parameter(name = "id", description = "编号", required = true)
  57 + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:delete')")
  58 + public CommonResult<Boolean> deleteDemo01Contact(@RequestParam("id") Long id) {
  59 + demo01ContactService.deleteDemo01Contact(id);
  60 + return success(true);
  61 + }
  62 +
  63 + @GetMapping("/get")
  64 + @Operation(summary = "获得示例联系人")
  65 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  66 + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:query')")
  67 + public CommonResult<Demo01ContactRespVO> getDemo01Contact(@RequestParam("id") Long id) {
  68 + Demo01ContactDO demo01Contact = demo01ContactService.getDemo01Contact(id);
  69 + return success(BeanUtils.toBean(demo01Contact, Demo01ContactRespVO.class));
  70 + }
  71 +
  72 + @GetMapping("/page")
  73 + @Operation(summary = "获得示例联系人分页")
  74 + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:query')")
  75 + public CommonResult<PageResult<Demo01ContactRespVO>> getDemo01ContactPage(@Valid Demo01ContactPageReqVO pageReqVO) {
  76 + PageResult<Demo01ContactDO> pageResult = demo01ContactService.getDemo01ContactPage(pageReqVO);
  77 + return success(BeanUtils.toBean(pageResult, Demo01ContactRespVO.class));
  78 + }
  79 +
  80 + @GetMapping("/export-excel")
  81 + @Operation(summary = "导出示例联系人 Excel")
  82 + @PreAuthorize("@ss.hasPermission('infra:demo01-contact:export')")
  83 + @OperateLog(type = EXPORT)
  84 + public void exportDemo01ContactExcel(@Valid Demo01ContactPageReqVO pageReqVO,
  85 + HttpServletResponse response) throws IOException {
  86 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  87 + List<Demo01ContactDO> list = demo01ContactService.getDemo01ContactPage(pageReqVO).getList();
  88 + // 导出 Excel
  89 + ExcelUtils.write(response, "示例联系人.xls", "数据", Demo01ContactRespVO.class,
  90 + BeanUtils.toBean(list, Demo01ContactRespVO.class));
  91 + }
  92 +
  93 +}
0 94 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoPageReqVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactPageReqVO.java 100755 → 100644
1   -package cn.iocoder.yudao.module.infra.controller.admin.test.vo;
2   -import io.swagger.v3.oas.annotations.media.Schema;
3   -import lombok.*;
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo;
4 2  
5   -import java.time.LocalDateTime;
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageParam;
7 7 import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
8 9  
9 10 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
10 11  
11   -@Schema(description = "管理后台 - 字典类型分页 Request VO")
  12 +@Schema(description = "管理后台 - 示例联系人分页 Request VO")
12 13 @Data
13 14 @EqualsAndHashCode(callSuper = true)
14 15 @ToString(callSuper = true)
15   -public class TestDemoPageReqVO extends PageParam {
  16 +public class Demo01ContactPageReqVO extends PageParam {
16 17  
17   - @Schema(description = "名字")
  18 + @Schema(description = "名字", example = "张三")
18 19 private String name;
19 20  
20   - @Schema(description = "状态")
21   - private Integer status;
  21 + @Schema(description = "性别", example = "1")
  22 + private Integer sex;
22 23  
23   - @Schema(description = "类型")
24   - private Integer type;
25   -
26   - @Schema(description = "分类")
27   - private Integer category;
28   -
29   - @Schema(description = "备注")
30   - private String remark;
31   -
32   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
33 24 @Schema(description = "创建时间")
  25 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
34 26 private LocalDateTime[] createTime;
35 27  
36 28 -}
  29 +}
37 30 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import java.util.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +import com.alibaba.excel.annotation.*;
  10 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  11 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  12 +
  13 +@Schema(description = "管理后台 - 示例联系人 Response VO")
  14 +@Data
  15 +@ExcelIgnoreUnannotated
  16 +public class Demo01ContactRespVO {
  17 +
  18 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21555")
  19 + @ExcelProperty("编号")
  20 + private Long id;
  21 +
  22 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
  23 + @ExcelProperty("名字")
  24 + private String name;
  25 +
  26 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  27 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  28 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  29 + private Integer sex;
  30 +
  31 + @Schema(description = "出生年", requiredMode = Schema.RequiredMode.REQUIRED)
  32 + @ExcelProperty("出生年")
  33 + private LocalDateTime birthday;
  34 +
  35 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
  36 + @ExcelProperty("简介")
  37 + private String description;
  38 +
  39 + @Schema(description = "头像")
  40 + @ExcelProperty("头像")
  41 + private String avatar;
  42 +
  43 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  44 + @ExcelProperty("创建时间")
  45 + private LocalDateTime createTime;
  46 +
  47 +}
0 48 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo01/vo/Demo01ContactSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +import javax.validation.constraints.NotNull;
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 示例联系人新增/修改 Request VO")
  11 +@Data
  12 +public class Demo01ContactSaveReqVO {
  13 +
  14 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "21555")
  15 + private Long id;
  16 +
  17 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
  18 + @NotEmpty(message = "名字不能为空")
  19 + private String name;
  20 +
  21 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  22 + @NotNull(message = "性别不能为空")
  23 + private Integer sex;
  24 +
  25 + @Schema(description = "出生年", requiredMode = Schema.RequiredMode.REQUIRED)
  26 + @NotNull(message = "出生年不能为空")
  27 + private LocalDateTime birthday;
  28 +
  29 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
  30 + @NotEmpty(message = "简介不能为空")
  31 + private String description;
  32 +
  33 + @Schema(description = "头像")
  34 + private String avatar;
  35 +
  36 +}
0 37 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/Demo02CategoryController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  5 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  6 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO;
  8 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryRespVO;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02.Demo02CategoryDO;
  11 +import cn.iocoder.yudao.module.infra.service.demo.demo02.Demo02CategoryService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.Parameter;
  14 +import io.swagger.v3.oas.annotations.tags.Tag;
  15 +import org.springframework.security.access.prepost.PreAuthorize;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import javax.annotation.Resource;
  20 +import javax.servlet.http.HttpServletResponse;
  21 +import javax.validation.Valid;
  22 +import java.io.IOException;
  23 +import java.util.List;
  24 +
  25 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  26 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
  27 +
  28 +@Tag(name = "管理后台 - 示例分类")
  29 +@RestController
  30 +@RequestMapping("/infra/demo02-category")
  31 +@Validated
  32 +public class Demo02CategoryController {
  33 +
  34 + @Resource
  35 + private Demo02CategoryService demo02CategoryService;
  36 +
  37 + @PostMapping("/create")
  38 + @Operation(summary = "创建示例分类")
  39 + @PreAuthorize("@ss.hasPermission('infra:demo02-category:create')")
  40 + public CommonResult<Long> createDemo02Category(@Valid @RequestBody Demo02CategorySaveReqVO createReqVO) {
  41 + return success(demo02CategoryService.createDemo02Category(createReqVO));
  42 + }
  43 +
  44 + @PutMapping("/update")
  45 + @Operation(summary = "更新示例分类")
  46 + @PreAuthorize("@ss.hasPermission('infra:demo02-category:update')")
  47 + public CommonResult<Boolean> updateDemo02Category(@Valid @RequestBody Demo02CategorySaveReqVO updateReqVO) {
  48 + demo02CategoryService.updateDemo02Category(updateReqVO);
  49 + return success(true);
  50 + }
  51 +
  52 + @DeleteMapping("/delete")
  53 + @Operation(summary = "删除示例分类")
  54 + @Parameter(name = "id", description = "编号", required = true)
  55 + @PreAuthorize("@ss.hasPermission('infra:demo02-category:delete')")
  56 + public CommonResult<Boolean> deleteDemo02Category(@RequestParam("id") Long id) {
  57 + demo02CategoryService.deleteDemo02Category(id);
  58 + return success(true);
  59 + }
  60 +
  61 + @GetMapping("/get")
  62 + @Operation(summary = "获得示例分类")
  63 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  64 + @PreAuthorize("@ss.hasPermission('infra:demo02-category:query')")
  65 + public CommonResult<Demo02CategoryRespVO> getDemo02Category(@RequestParam("id") Long id) {
  66 + Demo02CategoryDO demo02Category = demo02CategoryService.getDemo02Category(id);
  67 + return success(BeanUtils.toBean(demo02Category, Demo02CategoryRespVO.class));
  68 + }
  69 +
  70 + @GetMapping("/list")
  71 + @Operation(summary = "获得示例分类列表")
  72 + @PreAuthorize("@ss.hasPermission('infra:demo02-category:query')")
  73 + public CommonResult<List<Demo02CategoryRespVO>> getDemo02CategoryList(@Valid Demo02CategoryListReqVO listReqVO) {
  74 + List<Demo02CategoryDO> list = demo02CategoryService.getDemo02CategoryList(listReqVO);
  75 + return success(BeanUtils.toBean(list, Demo02CategoryRespVO.class));
  76 + }
  77 +
  78 + @GetMapping("/export-excel")
  79 + @Operation(summary = "导出示例分类 Excel")
  80 + @PreAuthorize("@ss.hasPermission('infra:demo02-category:export')")
  81 + @OperateLog(type = EXPORT)
  82 + public void exportDemo02CategoryExcel(@Valid Demo02CategoryListReqVO listReqVO,
  83 + HttpServletResponse response) throws IOException {
  84 + List<Demo02CategoryDO> list = demo02CategoryService.getDemo02CategoryList(listReqVO);
  85 + // 导出 Excel
  86 + ExcelUtils.write(response, "示例分类.xls", "数据", Demo02CategoryRespVO.class,
  87 + BeanUtils.toBean(list, Demo02CategoryRespVO.class));
  88 + }
  89 +
  90 +}
0 91 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoExportReqVO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryListReqVO.java 100755 → 100644
1   -package cn.iocoder.yudao.module.infra.controller.admin.test.vo;
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo;
  2 +
2 3 import io.swagger.v3.oas.annotations.media.Schema;
3   -import lombok.*;
  4 +import lombok.Data;
  5 +import org.springframework.format.annotation.DateTimeFormat;
4 6  
5 7 import java.time.LocalDateTime;
6   -import org.springframework.format.annotation.DateTimeFormat;
7 8  
8 9 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
9 10  
10   -@Schema(description = "管理后台 - 字典类型 Excel 导出 Request VO,参数和 TestDemoPageReqVO 是一致的")
  11 +@Schema(description = "管理后台 - 示例分类列表 Request VO")
11 12 @Data
12   -public class TestDemoExportReqVO {
  13 +public class Demo02CategoryListReqVO {
13 14  
14   - @Schema(description = "名字")
  15 + @Schema(description = "名字", example = "芋艿")
15 16 private String name;
16 17  
17   - @Schema(description = "状态")
18   - private Integer status;
19   -
20   - @Schema(description = "类型")
21   - private Integer type;
  18 + @Schema(description = "父级编号", example = "6080")
  19 + private Long parentId;
22 20  
23   - @Schema(description = "分类")
24   - private Integer category;
25   -
26   - @Schema(description = "备注")
27   - private String remark;
28   -
29   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
30 21 @Schema(description = "创建时间")
  22 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
31 23 private LocalDateTime[] createTime;
32 24  
33 25 -}
  26 +}
34 27 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategoryRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  4 +import com.alibaba.excel.annotation.ExcelProperty;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.Data;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - 示例分类 Response VO")
  11 +@Data
  12 +@ExcelIgnoreUnannotated
  13 +public class Demo02CategoryRespVO {
  14 +
  15 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10304")
  16 + @ExcelProperty("编号")
  17 + private Long id;
  18 +
  19 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
  20 + @ExcelProperty("名字")
  21 + private String name;
  22 +
  23 + @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6080")
  24 + @ExcelProperty("父级编号")
  25 + private Long parentId;
  26 +
  27 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + @ExcelProperty("创建时间")
  29 + private LocalDateTime createTime;
  30 +
  31 +}
0 32 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo02/vo/Demo02CategorySaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import javax.validation.constraints.NotEmpty;
  7 +import javax.validation.constraints.NotNull;
  8 +
  9 +@Schema(description = "管理后台 - 示例分类新增/修改 Request VO")
  10 +@Data
  11 +public class Demo02CategorySaveReqVO {
  12 +
  13 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "10304")
  14 + private Long id;
  15 +
  16 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
  17 + @NotEmpty(message = "名字不能为空")
  18 + private String name;
  19 +
  20 + @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6080")
  21 + @NotNull(message = "父级编号不能为空")
  22 + private Long parentId;
  23 +
  24 +}
0 25 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/Demo03StudentController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  8 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentRespVO;
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO;
  13 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO;
  14 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03StudentDO;
  15 +import cn.iocoder.yudao.module.infra.service.demo.demo03.Demo03StudentService;
  16 +import io.swagger.v3.oas.annotations.Operation;
  17 +import io.swagger.v3.oas.annotations.Parameter;
  18 +import io.swagger.v3.oas.annotations.tags.Tag;
  19 +import org.springframework.security.access.prepost.PreAuthorize;
  20 +import org.springframework.validation.annotation.Validated;
  21 +import org.springframework.web.bind.annotation.*;
  22 +
  23 +import javax.annotation.Resource;
  24 +import javax.servlet.http.HttpServletResponse;
  25 +import javax.validation.Valid;
  26 +import java.io.IOException;
  27 +import java.util.List;
  28 +
  29 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  30 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
  31 +
  32 +@Tag(name = "管理后台 - 学生")
  33 +@RestController
  34 +@RequestMapping("/infra/demo03-student")
  35 +@Validated
  36 +public class Demo03StudentController {
  37 +
  38 + @Resource
  39 + private Demo03StudentService demo03StudentService;
  40 +
  41 + @PostMapping("/create")
  42 + @Operation(summary = "创建学生")
  43 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')")
  44 + public CommonResult<Long> createDemo03Student(@Valid @RequestBody Demo03StudentSaveReqVO createReqVO) {
  45 + return success(demo03StudentService.createDemo03Student(createReqVO));
  46 + }
  47 +
  48 + @PutMapping("/update")
  49 + @Operation(summary = "更新学生")
  50 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')")
  51 + public CommonResult<Boolean> updateDemo03Student(@Valid @RequestBody Demo03StudentSaveReqVO updateReqVO) {
  52 + demo03StudentService.updateDemo03Student(updateReqVO);
  53 + return success(true);
  54 + }
  55 +
  56 + @DeleteMapping("/delete")
  57 + @Operation(summary = "删除学生")
  58 + @Parameter(name = "id", description = "编号", required = true)
  59 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')")
  60 + public CommonResult<Boolean> deleteDemo03Student(@RequestParam("id") Long id) {
  61 + demo03StudentService.deleteDemo03Student(id);
  62 + return success(true);
  63 + }
  64 +
  65 + @GetMapping("/get")
  66 + @Operation(summary = "获得学生")
  67 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  68 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')")
  69 + public CommonResult<Demo03StudentRespVO> getDemo03Student(@RequestParam("id") Long id) {
  70 + Demo03StudentDO demo03Student = demo03StudentService.getDemo03Student(id);
  71 + return success(BeanUtils.toBean(demo03Student, Demo03StudentRespVO.class));
  72 + }
  73 +
  74 + @GetMapping("/page")
  75 + @Operation(summary = "获得学生分页")
  76 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')")
  77 + public CommonResult<PageResult<Demo03StudentRespVO>> getDemo03StudentPage(@Valid Demo03StudentPageReqVO pageReqVO) {
  78 + PageResult<Demo03StudentDO> pageResult = demo03StudentService.getDemo03StudentPage(pageReqVO);
  79 + return success(BeanUtils.toBean(pageResult, Demo03StudentRespVO.class));
  80 + }
  81 +
  82 + @GetMapping("/export-excel")
  83 + @Operation(summary = "导出学生 Excel")
  84 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:export')")
  85 + @OperateLog(type = EXPORT)
  86 + public void exportDemo03StudentExcel(@Valid Demo03StudentPageReqVO pageReqVO,
  87 + HttpServletResponse response) throws IOException {
  88 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  89 + List<Demo03StudentDO> list = demo03StudentService.getDemo03StudentPage(pageReqVO).getList();
  90 + // 导出 Excel
  91 + ExcelUtils.write(response, "学生.xls", "数据", Demo03StudentRespVO.class,
  92 + BeanUtils.toBean(list, Demo03StudentRespVO.class));
  93 + }
  94 +
  95 + // ==================== 子表(学生课程) ====================
  96 +
  97 + @GetMapping("/demo03-course/page")
  98 + @Operation(summary = "获得学生课程分页")
  99 + @Parameter(name = "studentId", description = "学生编号")
  100 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')")
  101 + public CommonResult<PageResult<Demo03CourseDO>> getDemo03CoursePage(PageParam pageReqVO,
  102 + @RequestParam("studentId") Long studentId) {
  103 + return success(demo03StudentService.getDemo03CoursePage(pageReqVO, studentId));
  104 + }
  105 +
  106 + @PostMapping("/demo03-course/create")
  107 + @Operation(summary = "创建学生课程")
  108 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')")
  109 + public CommonResult<Long> createDemo03Course(@Valid @RequestBody Demo03CourseDO demo03Course) {
  110 + return success(demo03StudentService.createDemo03Course(demo03Course));
  111 + }
  112 +
  113 + @PutMapping("/demo03-course/update")
  114 + @Operation(summary = "更新学生课程")
  115 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')")
  116 + public CommonResult<Boolean> updateDemo03Course(@Valid @RequestBody Demo03CourseDO demo03Course) {
  117 + demo03StudentService.updateDemo03Course(demo03Course);
  118 + return success(true);
  119 + }
  120 +
  121 + @DeleteMapping("/demo03-course/delete")
  122 + @Parameter(name = "id", description = "编号", required = true)
  123 + @Operation(summary = "删除学生课程")
  124 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')")
  125 + public CommonResult<Boolean> deleteDemo03Course(@RequestParam("id") Long id) {
  126 + demo03StudentService.deleteDemo03Course(id);
  127 + return success(true);
  128 + }
  129 +
  130 + @GetMapping("/demo03-course/get")
  131 + @Operation(summary = "获得学生课程")
  132 + @Parameter(name = "id", description = "编号", required = true)
  133 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')")
  134 + public CommonResult<Demo03CourseDO> getDemo03Course(@RequestParam("id") Long id) {
  135 + return success(demo03StudentService.getDemo03Course(id));
  136 + }
  137 +
  138 + @GetMapping("/demo03-course/list-by-student-id")
  139 + @Operation(summary = "获得学生课程列表")
  140 + @Parameter(name = "studentId", description = "学生编号")
  141 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')")
  142 + public CommonResult<List<Demo03CourseDO>> getDemo03CourseListByStudentId(@RequestParam("studentId") Long studentId) {
  143 + return success(demo03StudentService.getDemo03CourseListByStudentId(studentId));
  144 + }
  145 +
  146 + // ==================== 子表(学生班级) ====================
  147 +
  148 + @GetMapping("/demo03-grade/page")
  149 + @Operation(summary = "获得学生班级分页")
  150 + @Parameter(name = "studentId", description = "学生编号")
  151 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')")
  152 + public CommonResult<PageResult<Demo03GradeDO>> getDemo03GradePage(PageParam pageReqVO,
  153 + @RequestParam("studentId") Long studentId) {
  154 + return success(demo03StudentService.getDemo03GradePage(pageReqVO, studentId));
  155 + }
  156 +
  157 + @PostMapping("/demo03-grade/create")
  158 + @Operation(summary = "创建学生班级")
  159 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:create')")
  160 + public CommonResult<Long> createDemo03Grade(@Valid @RequestBody Demo03GradeDO demo03Grade) {
  161 + return success(demo03StudentService.createDemo03Grade(demo03Grade));
  162 + }
  163 +
  164 + @PutMapping("/demo03-grade/update")
  165 + @Operation(summary = "更新学生班级")
  166 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:update')")
  167 + public CommonResult<Boolean> updateDemo03Grade(@Valid @RequestBody Demo03GradeDO demo03Grade) {
  168 + demo03StudentService.updateDemo03Grade(demo03Grade);
  169 + return success(true);
  170 + }
  171 +
  172 + @DeleteMapping("/demo03-grade/delete")
  173 + @Parameter(name = "id", description = "编号", required = true)
  174 + @Operation(summary = "删除学生班级")
  175 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:delete')")
  176 + public CommonResult<Boolean> deleteDemo03Grade(@RequestParam("id") Long id) {
  177 + demo03StudentService.deleteDemo03Grade(id);
  178 + return success(true);
  179 + }
  180 +
  181 + @GetMapping("/demo03-grade/get")
  182 + @Operation(summary = "获得学生班级")
  183 + @Parameter(name = "id", description = "编号", required = true)
  184 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')")
  185 + public CommonResult<Demo03GradeDO> getDemo03Grade(@RequestParam("id") Long id) {
  186 + return success(demo03StudentService.getDemo03Grade(id));
  187 + }
  188 +
  189 + @GetMapping("/demo03-grade/get-by-student-id")
  190 + @Operation(summary = "获得学生班级")
  191 + @Parameter(name = "studentId", description = "学生编号")
  192 + @PreAuthorize("@ss.hasPermission('infra:demo03-student:query')")
  193 + public CommonResult<Demo03GradeDO> getDemo03GradeByStudentId(@RequestParam("studentId") Long studentId) {
  194 + return success(demo03StudentService.getDemo03GradeByStudentId(studentId));
  195 + }
  196 +
  197 +}
0 198 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03;
0 2 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo;
  2 +
  3 +import lombok.*;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +import java.time.LocalDateTime;
  8 +
  9 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  10 +
  11 +@Schema(description = "管理后台 - 学生分页 Request VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class Demo03StudentPageReqVO extends PageParam {
  16 +
  17 + @Schema(description = "名字", example = "芋艿")
  18 + private String name;
  19 +
  20 + @Schema(description = "性别")
  21 + private Integer sex;
  22 +
  23 + @Schema(description = "简介", example = "随便")
  24 + private String description;
  25 +
  26 + @Schema(description = "创建时间")
  27 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  28 + private LocalDateTime[] createTime;
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +
  6 +import java.time.LocalDateTime;
  7 +import com.alibaba.excel.annotation.*;
  8 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  9 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  10 +
  11 +@Schema(description = "管理后台 - 学生 Response VO")
  12 +@Data
  13 +@ExcelIgnoreUnannotated
  14 +public class Demo03StudentRespVO {
  15 +
  16 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8525")
  17 + @ExcelProperty("编号")
  18 + private Long id;
  19 +
  20 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
  21 + @ExcelProperty("名字")
  22 + private String name;
  23 +
  24 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  26 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  27 + private Integer sex;
  28 +
  29 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  30 + @ExcelProperty("出生日期")
  31 + private LocalDateTime birthday;
  32 +
  33 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "随便")
  34 + @ExcelProperty("简介")
  35 + private String description;
  36 +
  37 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  38 + @ExcelProperty("创建时间")
  39 + private LocalDateTime createTime;
  40 +
  41 +}
0 42 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/demo03/vo/Demo03StudentSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import javax.validation.constraints.*;
  7 +import java.time.LocalDateTime;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO;
  10 +
  11 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  12 +@Data
  13 +public class Demo03StudentSaveReqVO {
  14 +
  15 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8525")
  16 + private Long id;
  17 +
  18 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
  19 + @NotEmpty(message = "名字不能为空")
  20 + private String name;
  21 +
  22 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED)
  23 + @NotNull(message = "性别不能为空")
  24 + private Integer sex;
  25 +
  26 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  27 + @NotNull(message = "出生日期不能为空")
  28 + private LocalDateTime birthday;
  29 +
  30 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "随便")
  31 + @NotEmpty(message = "简介不能为空")
  32 + private String description;
  33 +
  34 +
  35 + private List<Demo03CourseDO> demo03Courses;
  36 +
  37 + private Demo03GradeDO demo03Grade;
  38 +
  39 +}
0 40 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/package-info.java 0 → 100644
  1 +/**
  2 + * 代码生成示例
  3 + *
  4 + * 1. demo01:单表(增删改查)
  5 + * 2. demo02:单表(树形结构)
  6 + * 3. demo03:主子表(标准模式)+ 主子表(ERP 模式)+ 主子表(内嵌模式)
  7 + */
  8 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
0 9 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/TestDemoController.http deleted
1   -### 请求 /infra/test-demo/get 接口 => 成功
2   -GET {{baseUrl}}/infra/test-demo/get?id=106
3   -Authorization: Bearer {{token}}
4   -tenant-id: {{adminTenentId}}
5   -
6   -### 请求 /infra/test-demo/update 接口 => 成功
7   -PUT {{baseUrl}}/infra/test-demo/update
8   -Authorization: Bearer {{token}}
9   -tenant-id: {{adminTenentId}}
10   -Content-Type: application/json
11   -
12   -
13   -{
14   - "id": 106,
15   - "name": "测试",
16   - "status": "0",
17   - "type": 1,
18   - "category": 1
19   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/TestDemoController.java deleted
1   -package cn.iocoder.yudao.module.infra.controller.admin.test;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
6   -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
7   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.*;
8   -import cn.iocoder.yudao.module.infra.convert.test.TestDemoConvert;
9   -import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
10   -import cn.iocoder.yudao.module.infra.service.test.TestDemoService;
11   -import io.swagger.v3.oas.annotations.tags.Tag;
12   -import io.swagger.v3.oas.annotations.Parameter;
13   -import io.swagger.v3.oas.annotations.Operation;
14   -import org.springframework.security.access.prepost.PreAuthorize;
15   -import org.springframework.validation.annotation.Validated;
16   -import org.springframework.web.bind.annotation.*;
17   -
18   -import javax.annotation.Resource;
19   -import javax.servlet.http.HttpServletResponse;
20   -import javax.validation.Valid;
21   -import java.io.IOException;
22   -import java.util.Collection;
23   -import java.util.List;
24   -
25   -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
26   -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
27   -
28   -@Tag(name = "管理后台 - 字典类型")
29   -@RestController
30   -@RequestMapping("/infra/test-demo")
31   -@Validated
32   -public class TestDemoController {
33   -
34   - @Resource
35   - private TestDemoService testDemoService;
36   -
37   - @PostMapping("/create")
38   - @Operation(summary = "创建字典类型")
39   - @PreAuthorize("@ss.hasPermission('infra:test-demo:create')")
40   - public CommonResult<Long> createTestDemo(@Valid @RequestBody TestDemoCreateReqVO createReqVO) {
41   - return success(testDemoService.createTestDemo(createReqVO));
42   - }
43   -
44   - @PutMapping("/update")
45   - @Operation(summary = "更新字典类型")
46   - @PreAuthorize("@ss.hasPermission('infra:test-demo:update')")
47   - public CommonResult<Boolean> updateTestDemo(@Valid @RequestBody TestDemoUpdateReqVO updateReqVO) {
48   - testDemoService.updateTestDemo(updateReqVO);
49   - return success(true);
50   - }
51   -
52   - @DeleteMapping("/delete")
53   - @Operation(summary = "删除字典类型")
54   - @Parameter(name = "id", description = "编号", required = true)
55   - @PreAuthorize("@ss.hasPermission('infra:test-demo:delete')")
56   - public CommonResult<Boolean> deleteTestDemo(@RequestParam("id") Long id) {
57   - testDemoService.deleteTestDemo(id);
58   - return success(true);
59   - }
60   -
61   - @GetMapping("/get")
62   - @Operation(summary = "获得字典类型")
63   - @Parameter(name = "id", description = "编号", required = true, example = "1024")
64   - @PreAuthorize("@ss.hasPermission('infra:test-demo:query')")
65   - public CommonResult<TestDemoRespVO> getTestDemo(@RequestParam("id") Long id) {
66   - TestDemoDO testDemo = testDemoService.getTestDemo(id);
67   - return success(TestDemoConvert.INSTANCE.convert(testDemo));
68   - }
69   -
70   - @GetMapping("/list")
71   - @Operation(summary = "获得字典类型列表")
72   - @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
73   - @PreAuthorize("@ss.hasPermission('infra:test-demo:query')")
74   - public CommonResult<List<TestDemoRespVO>> getTestDemoList(@RequestParam("ids") Collection<Long> ids) {
75   - List<TestDemoDO> list = testDemoService.getTestDemoList(ids);
76   - return success(TestDemoConvert.INSTANCE.convertList(list));
77   - }
78   -
79   - @GetMapping("/page")
80   - @Operation(summary = "获得字典类型分页")
81   - @PreAuthorize("@ss.hasPermission('infra:test-demo:query')") public CommonResult<PageResult<TestDemoRespVO>> getTestDemoPage(@Valid TestDemoPageReqVO pageVO) {
82   - PageResult<TestDemoDO> pageResult = testDemoService.getTestDemoPage(pageVO);
83   - return success(TestDemoConvert.INSTANCE.convertPage(pageResult));
84   - }
85   -
86   - @GetMapping("/export-excel")
87   - @Operation(summary = "导出字典类型 Excel")
88   - @PreAuthorize("@ss.hasPermission('infra:test-demo:export')") @OperateLog(type = EXPORT)
89   - public void exportTestDemoExcel(@Valid TestDemoExportReqVO exportReqVO,
90   - HttpServletResponse response) throws IOException {
91   - List<TestDemoDO> list = testDemoService.getTestDemoList(exportReqVO);
92   - // 导出 Excel
93   - List<TestDemoExcelVO> datas = TestDemoConvert.INSTANCE.convertList02(list);
94   - ExcelUtils.write(response, "字典类型.xls", "数据", TestDemoExcelVO.class, datas);
95   - }
96   -
97   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoBaseVO.java deleted
1   -package cn.iocoder.yudao.module.infra.controller.admin.test.vo;
2   -import io.swagger.v3.oas.annotations.media.Schema;
3   -import lombok.*;
4   -import javax.validation.constraints.*;
5   -
6   -/**
7   -* 字典类型 Base VO,提供给添加、修改、详细的子 VO 使用
8   -* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
9   -*/
10   -@Data
11   -public class TestDemoBaseVO {
12   -
13   - @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED)
14   - @NotNull(message = "名字不能为空")
15   - private String name;
16   -
17   - @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED)
18   - @NotNull(message = "状态不能为空")
19   - private Integer status;
20   -
21   - @Schema(description = "类型", requiredMode = Schema.RequiredMode.REQUIRED)
22   - @NotNull(message = "类型不能为空")
23   - private Integer type;
24   -
25   - @Schema(description = "分类", requiredMode = Schema.RequiredMode.REQUIRED)
26   - @NotNull(message = "分类不能为空")
27   - private Integer category;
28   -
29   - @Schema(description = "备注")
30   - private String remark;
31   -
32   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoCreateReqVO.java deleted
1   -package cn.iocoder.yudao.module.infra.controller.admin.test.vo;
2   -import io.swagger.v3.oas.annotations.media.Schema;
3   -import lombok.*;
4   -
5   -@Schema(description = "管理后台 - 字典类型创建 Request VO")
6   -@Data
7   -@EqualsAndHashCode(callSuper = true)
8   -@ToString(callSuper = true)
9   -public class TestDemoCreateReqVO extends TestDemoBaseVO {
10   -
11   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoExcelVO.java deleted
1   -package cn.iocoder.yudao.module.infra.controller.admin.test.vo;
2   -
3   -import lombok.*;
4   -
5   -import java.time.LocalDateTime;
6   -
7   -import com.alibaba.excel.annotation.ExcelProperty;
8   -
9   -/**
10   - * 字典类型 Excel VO
11   - *
12   - * @author 芋道源码
13   - */
14   -@Data
15   -public class TestDemoExcelVO {
16   -
17   - @ExcelProperty("编号")
18   - private Long id;
19   -
20   - @ExcelProperty("名字")
21   - private String name;
22   -
23   - @ExcelProperty("状态")
24   - private Integer status;
25   -
26   - @ExcelProperty("类型")
27   - private Integer type;
28   -
29   - @ExcelProperty("分类")
30   - private Integer category;
31   -
32   - @ExcelProperty("备注")
33   - private String remark;
34   -
35   - @ExcelProperty("创建时间")
36   - private LocalDateTime createTime;
37   -
38   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoRespVO.java deleted
1   -package cn.iocoder.yudao.module.infra.controller.admin.test.vo;
2   -import io.swagger.v3.oas.annotations.media.Schema;
3   -import lombok.*;
4   -
5   -import java.time.LocalDateTime;
6   -
7   -@Schema(description = "管理后台 - 字典类型 Response VO")
8   -@Data
9   -@EqualsAndHashCode(callSuper = true)
10   -@ToString(callSuper = true)
11   -public class TestDemoRespVO extends TestDemoBaseVO {
12   -
13   - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED)
14   - private Long id;
15   -
16   - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
17   - private LocalDateTime createTime;
18   -
19   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/test/vo/TestDemoUpdateReqVO.java deleted
1   -package cn.iocoder.yudao.module.infra.controller.admin.test.vo;
2   -import io.swagger.v3.oas.annotations.media.Schema;
3   -import lombok.*;
4   -import javax.validation.constraints.*;
5   -
6   -@Schema(description = "管理后台 - 字典类型更新 Request VO")
7   -@Data
8   -@EqualsAndHashCode(callSuper = true)
9   -@ToString(callSuper = true)
10   -public class TestDemoUpdateReqVO extends TestDemoBaseVO {
11   -
12   - @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED)
13   - @NotNull(message = "编号不能为空")
14   - private Long id;
15   -
16   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
... ... @@ -56,7 +56,7 @@ public interface CodegenConvert {
56 56  
57 57 // ========== CodegenTableDO 相关 ==========
58 58  
59   -// List<CodegenTableRespVO> convertList02(List<CodegenTableDO> list);
  59 + List<CodegenTableRespVO> convertList05(List<CodegenTableDO> list);
60 60  
61 61 CodegenTableRespVO convert(CodegenTableDO bean);
62 62  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/test/TestDemoConvert.java deleted
1   -package cn.iocoder.yudao.module.infra.convert.test;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoCreateReqVO;
5   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoExcelVO;
6   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoRespVO;
7   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoUpdateReqVO;
8   -import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
9   -import org.mapstruct.Mapper;
10   -import org.mapstruct.factory.Mappers;
11   -
12   -import java.util.List;
13   -
14   -/**
15   - * 字典类型 Convert
16   - *
17   - * @author 芋道源码
18   - */
19   -@Mapper
20   -public interface TestDemoConvert {
21   -
22   - TestDemoConvert INSTANCE = Mappers.getMapper(TestDemoConvert.class);
23   -
24   - TestDemoDO convert(TestDemoCreateReqVO bean);
25   -
26   - TestDemoDO convert(TestDemoUpdateReqVO bean);
27   -
28   - TestDemoRespVO convert(TestDemoDO bean);
29   -
30   - List<TestDemoRespVO> convertList(List<TestDemoDO> list);
31   -
32   - PageResult<TestDemoRespVO> convertPage(PageResult<TestDemoDO> page);
33   -
34   - List<TestDemoExcelVO> convertList02(List<TestDemoDO> list);
35   -
36   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenTableDO.java
... ... @@ -116,4 +116,43 @@ public class CodegenTableDO extends BaseDO {
116 116 */
117 117 private Long parentMenuId;
118 118  
  119 + // ========== 主子表相关字段 ==========
  120 +
  121 + /**
  122 + * 主表的编号
  123 + *
  124 + * 关联 {@link CodegenTableDO#getId()}
  125 + */
  126 + private Long masterTableId;
  127 + /**
  128 + * 【自己】子表关联主表的字段编号
  129 + *
  130 + * 关联 {@link CodegenColumnDO#getId()}
  131 + */
  132 + private Long subJoinColumnId;
  133 + /**
  134 + * 主表与子表是否一对多
  135 + *
  136 + * true:一对多
  137 + * false:一对一
  138 + */
  139 + private Boolean subJoinMany;
  140 +
  141 + // ========== 树表相关字段 ==========
  142 +
  143 + /**
  144 + * 树表的父字段编号
  145 + *
  146 + * 关联 {@link CodegenColumnDO#getId()}
  147 + */
  148 + private Long treeParentColumnId;
  149 + /**
  150 + * 树表的名字字段编号
  151 + *
  152 + * 名字的用途:新增或修改时,select 框展示的字段
  153 + *
  154 + * 关联 {@link CodegenColumnDO#getId()}
  155 + */
  156 + private Long treeNameColumnId;
  157 +
119 158 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/test/TestDemoDO.java renamed to yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo01/Demo01ContactDO.java 100755 → 100644
1   -package cn.iocoder.yudao.module.infra.dal.dataobject.test;
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01;
2 2  
3   -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4   -import com.baomidou.mybatisplus.annotation.KeySequence;
5   -import com.baomidou.mybatisplus.annotation.TableId;
6   -import com.baomidou.mybatisplus.annotation.TableName;
7 3 import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import java.time.LocalDateTime;
  8 +import com.baomidou.mybatisplus.annotation.*;
  9 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
8 10  
9 11 /**
10   - * 字典类型 DO
  12 + * 示例联系人 DO
11 13 *
12 14 * @author 芋道源码
13 15 */
14   -@TableName("infra_test_demo")
15   -@KeySequence("infra_test_demo_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  16 +@TableName("infra_demo01_contact")
  17 +@KeySequence("infra_demo01_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
16 18 @Data
17 19 @EqualsAndHashCode(callSuper = true)
18 20 @ToString(callSuper = true)
19 21 @Builder
20 22 @NoArgsConstructor
21 23 @AllArgsConstructor
22   -public class TestDemoDO extends BaseDO {
  24 +public class Demo01ContactDO extends BaseDO {
23 25  
24 26 /**
25 27 * 编号
... ... @@ -31,20 +33,22 @@ public class TestDemoDO extends BaseDO {
31 33 */
32 34 private String name;
33 35 /**
34   - * 状态
  36 + * 性别
  37 + *
  38 + * 枚举 {@link TODO system_user_sex 对应的类}
35 39 */
36   - private Integer status;
  40 + private Integer sex;
37 41 /**
38   - * 类型
  42 + * 出生年
39 43 */
40   - private Integer type;
  44 + private LocalDateTime birthday;
41 45 /**
42   - * 分类
  46 + * 简介
43 47 */
44   - private Integer category;
  48 + private String description;
45 49 /**
46   - * 备注
  50 + * 头像
47 51 */
48   - private String remark;
  52 + private String avatar;
49 53  
50 54 -}
  55 +}
51 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo02/Demo02CategoryDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 示例分类 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_demo02_category")
  16 +@KeySequence("infra_demo02_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class Demo02CategoryDO extends BaseDO {
  24 +
  25 + public static final Long PARENT_ID_ROOT = 0L;
  26 +
  27 + /**
  28 + * 编号
  29 + */
  30 + @TableId
  31 + private Long id;
  32 + /**
  33 + * 名字
  34 + */
  35 + private String name;
  36 + /**
  37 + * 父级编号
  38 + */
  39 + private Long parentId;
  40 +
  41 +}
0 42 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03CourseDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生课程 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_demo03_course")
  16 +@KeySequence("infra_demo03_course_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class Demo03CourseDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 学生编号
  32 + */
  33 + private Long studentId;
  34 + /**
  35 + * 名字
  36 + */
  37 + private String name;
  38 + /**
  39 + * 分数
  40 + */
  41 + private Integer score;
  42 +
  43 +}
0 44 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03GradeDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生班级 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_demo03_grade")
  16 +@KeySequence("infra_demo03_grade_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class Demo03GradeDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 学生编号
  32 + */
  33 + private Long studentId;
  34 + /**
  35 + * 名字
  36 + */
  37 + private String name;
  38 + /**
  39 + * 班主任
  40 + */
  41 + private String teacher;
  42 +
  43 +}
0 44 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/demo03/Demo03StudentDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import java.time.LocalDateTime;
  8 +import com.baomidou.mybatisplus.annotation.*;
  9 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  10 +
  11 +/**
  12 + * 学生 DO
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@TableName("infra_demo03_student")
  17 +@KeySequence("infra_demo03_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +@Builder
  22 +@NoArgsConstructor
  23 +@AllArgsConstructor
  24 +public class Demo03StudentDO extends BaseDO {
  25 +
  26 + /**
  27 + * 编号
  28 + */
  29 + @TableId
  30 + private Long id;
  31 + /**
  32 + * 名字
  33 + */
  34 + private String name;
  35 + /**
  36 + * 性别
  37 + *
  38 + * 枚举 {@link TODO system_user_sex 对应的类}
  39 + */
  40 + private Integer sex;
  41 + /**
  42 + * 出生日期
  43 + */
  44 + private LocalDateTime birthday;
  45 + /**
  46 + * 简介
  47 + */
  48 + private String description;
  49 +
  50 +}
0 51 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/CodegenTableMapper.java
... ... @@ -29,4 +29,9 @@ public interface CodegenTableMapper extends BaseMapperX&lt;CodegenTableDO&gt; {
29 29 return selectList(CodegenTableDO::getDataSourceConfigId, dataSourceConfigId);
30 30 }
31 31  
  32 + default List<CodegenTableDO> selectListByTemplateTypeAndMasterTableId(Integer templateType, Long masterTableId) {
  33 + return selectList(CodegenTableDO::getTemplateType, templateType,
  34 + CodegenTableDO::getMasterTableId, masterTableId);
  35 + }
  36 +
32 37 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo01/Demo01ContactMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo01;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01.Demo01ContactDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * 示例联系人 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface Demo01ContactMapper extends BaseMapperX<Demo01ContactDO> {
  17 +
  18 + default PageResult<Demo01ContactDO> selectPage(Demo01ContactPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<Demo01ContactDO>()
  20 + .likeIfPresent(Demo01ContactDO::getName, reqVO.getName())
  21 + .eqIfPresent(Demo01ContactDO::getSex, reqVO.getSex())
  22 + .betweenIfPresent(Demo01ContactDO::getCreateTime, reqVO.getCreateTime())
  23 + .orderByDesc(Demo01ContactDO::getId));
  24 + }
  25 +
  26 +}
0 27 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo02/Demo02CategoryMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo02;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02.Demo02CategoryDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +
  11 +/**
  12 + * 示例分类 Mapper
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@Mapper
  17 +public interface Demo02CategoryMapper extends BaseMapperX<Demo02CategoryDO> {
  18 +
  19 + default List<Demo02CategoryDO> selectList(Demo02CategoryListReqVO reqVO) {
  20 + return selectList(new LambdaQueryWrapperX<Demo02CategoryDO>()
  21 + .likeIfPresent(Demo02CategoryDO::getName, reqVO.getName())
  22 + .eqIfPresent(Demo02CategoryDO::getParentId, reqVO.getParentId())
  23 + .betweenIfPresent(Demo02CategoryDO::getCreateTime, reqVO.getCreateTime())
  24 + .orderByDesc(Demo02CategoryDO::getId));
  25 + }
  26 +
  27 + default Demo02CategoryDO selectByParentIdAndName(Long parentId, String name) {
  28 + return selectOne(Demo02CategoryDO::getParentId, parentId, Demo02CategoryDO::getName, name);
  29 + }
  30 +
  31 + default Long selectCountByParentId(Long parentId) {
  32 + return selectCount(Demo02CategoryDO::getParentId, parentId);
  33 + }
  34 +
  35 +}
0 36 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03CourseMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * 学生课程 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface Demo03CourseMapper extends BaseMapperX<Demo03CourseDO> {
  19 +
  20 + default PageResult<Demo03CourseDO> selectPage(PageParam reqVO, Long studentId) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<Demo03CourseDO>()
  22 + .eq(Demo03CourseDO::getStudentId, studentId)
  23 + .orderByDesc(Demo03CourseDO::getId));
  24 + }
  25 +
  26 + default List<Demo03CourseDO> selectListByStudentId(Long studentId) {
  27 + return selectList(Demo03CourseDO::getStudentId, studentId);
  28 + }
  29 +
  30 + default int deleteByStudentId(Long studentId) {
  31 + return delete(Demo03CourseDO::getStudentId, studentId);
  32 + }
  33 +
  34 +}
0 35 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03GradeMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * 学生班级 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface Demo03GradeMapper extends BaseMapperX<Demo03GradeDO> {
  17 +
  18 + default PageResult<Demo03GradeDO> selectPage(PageParam reqVO, Long studentId) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<Demo03GradeDO>()
  20 + .eq(Demo03GradeDO::getStudentId, studentId)
  21 + .orderByDesc(Demo03GradeDO::getId));
  22 + }
  23 +
  24 + default Demo03GradeDO selectByStudentId(Long studentId) {
  25 + return selectOne(Demo03GradeDO::getStudentId, studentId);
  26 + }
  27 +
  28 + default int deleteByStudentId(Long studentId) {
  29 + return delete(Demo03GradeDO::getStudentId, studentId);
  30 + }
  31 +
  32 +}
0 33 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/demo03/Demo03StudentMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03StudentDO;
  7 +import org.apache.ibatis.annotations.Mapper;
  8 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.*;
  9 +
  10 +/**
  11 + * 学生 Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface Demo03StudentMapper extends BaseMapperX<Demo03StudentDO> {
  17 +
  18 + default PageResult<Demo03StudentDO> selectPage(Demo03StudentPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<Demo03StudentDO>()
  20 + .likeIfPresent(Demo03StudentDO::getName, reqVO.getName())
  21 + .eqIfPresent(Demo03StudentDO::getSex, reqVO.getSex())
  22 + .eqIfPresent(Demo03StudentDO::getDescription, reqVO.getDescription())
  23 + .betweenIfPresent(Demo03StudentDO::getCreateTime, reqVO.getCreateTime())
  24 + .orderByDesc(Demo03StudentDO::getId));
  25 + }
  26 +
  27 +}
0 28 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/test/TestDemoMapper.java deleted
1   -package cn.iocoder.yudao.module.infra.dal.mysql.test;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5   -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoExportReqVO;
7   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoPageReqVO;
8   -import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
9   -import org.apache.ibatis.annotations.Mapper;
10   -
11   -import java.util.List;
12   -
13   -/**
14   - * 字典类型 Mapper
15   - *
16   - * @author 芋道源码
17   - */
18   -@Mapper
19   -public interface TestDemoMapper extends BaseMapperX<TestDemoDO> {
20   -
21   - default PageResult<TestDemoDO> selectPage(TestDemoPageReqVO reqVO) {
22   - return selectPage(reqVO, new LambdaQueryWrapperX<TestDemoDO>()
23   - .likeIfPresent(TestDemoDO::getName, reqVO.getName())
24   - .eqIfPresent(TestDemoDO::getStatus, reqVO.getStatus())
25   - .eqIfPresent(TestDemoDO::getType, reqVO.getType())
26   - .eqIfPresent(TestDemoDO::getCategory, reqVO.getCategory())
27   - .eqIfPresent(TestDemoDO::getRemark, reqVO.getRemark())
28   - .betweenIfPresent(TestDemoDO::getCreateTime, reqVO.getCreateTime())
29   - .orderByDesc(TestDemoDO::getId));
30   - }
31   -
32   - default List<TestDemoDO> selectList(TestDemoExportReqVO reqVO) {
33   - return selectList(new LambdaQueryWrapperX<TestDemoDO>()
34   - .likeIfPresent(TestDemoDO::getName, reqVO.getName())
35   - .eqIfPresent(TestDemoDO::getStatus, reqVO.getStatus())
36   - .eqIfPresent(TestDemoDO::getType, reqVO.getType())
37   - .eqIfPresent(TestDemoDO::getCategory, reqVO.getCategory())
38   - .eqIfPresent(TestDemoDO::getRemark, reqVO.getRemark())
39   - .betweenIfPresent(TestDemoDO::getCreateTime, reqVO.getCreateTime())
40   - .orderByDesc(TestDemoDO::getId));
41   - }
42   -
43   - List<TestDemoDO> selectList2();
44   -
45   -}
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenColumnHtmlTypeEnum.java
... ... @@ -16,8 +16,8 @@ public enum CodegenColumnHtmlTypeEnum {
16 16 RADIO("radio"), // 单选框
17 17 CHECKBOX("checkbox"), // 复选框
18 18 DATETIME("datetime"), // 日期控件
19   - UPLOAD_IMAGE("upload_image"), // 上传图片
20   - UPLOAD_FILE("upload_file"), // 上传文件
  19 + IMAGE_UPLOAD("imageUpload"), // 上传图片
  20 + FILE_UPLOAD("fileUpload"), // 上传文件
21 21 EDITOR("editor"), // 富文本控件
22 22 ;
23 23  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenTemplateTypeEnum.java
1 1 package cn.iocoder.yudao.module.infra.enums.codegen;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
3 4 import lombok.AllArgsConstructor;
4 5 import lombok.Getter;
5 6  
  7 +import java.util.Objects;
  8 +
6 9 /**
7 10 * 代码生成模板类型
8 11 *
... ... @@ -12,8 +15,13 @@ import lombok.Getter;
12 15 @Getter
13 16 public enum CodegenTemplateTypeEnum {
14 17  
15   - CRUD(1), // 单表(增删改查)
  18 + ONE(1), // 单表(增删改查)
16 19 TREE(2), // 树表(增删改查)
  20 +
  21 + MASTER_NORMAL(10), // 主子表 - 主表 - 普通模式
  22 + MASTER_ERP(11), // 主子表 - 主表 - ERP 模式
  23 + MASTER_INNER(12), // 主子表 - 主表 - 内嵌模式
  24 + SUB(15), // 主子表 - 子表
17 25 ;
18 26  
19 27 /**
... ... @@ -21,4 +29,25 @@ public enum CodegenTemplateTypeEnum {
21 29 */
22 30 private final Integer type;
23 31  
  32 + /**
  33 + * 是否为主表
  34 + *
  35 + * @param type 类型
  36 + * @return 是否主表
  37 + */
  38 + public static boolean isMaster(Integer type) {
  39 + return ObjectUtils.equalsAny(type,
  40 + MASTER_NORMAL.type, MASTER_ERP.type, MASTER_INNER.type);
  41 + }
  42 +
  43 + /**
  44 + * 是否为树表
  45 + *
  46 + * @param type 类型
  47 + * @return 是否树表
  48 + */
  49 + public static boolean isTree(Integer type) {
  50 + return Objects.equals(type, TREE.type);
  51 + }
  52 +
24 53 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenService.java
... ... @@ -49,6 +49,14 @@ public interface CodegenService {
49 49 void deleteCodegen(Long tableId);
50 50  
51 51 /**
  52 + * 获得表定义列表
  53 + *
  54 + * @param dataSourceConfigId 数据源配置的编号
  55 + * @return 表定义列表
  56 + */
  57 + List<CodegenTableDO> getCodegenTableList(Long dataSourceConfigId);
  58 +
  59 + /**
52 60 * 获得表定义分页
53 61 *
54 62 * @param pageReqVO 分页条件
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImpl.java
... ... @@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
14 14 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
15 15 import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
16 16 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  17 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
17 18 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
18 19 import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenBuilder;
19 20 import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
... ... @@ -25,10 +26,7 @@ import org.springframework.stereotype.Service;
25 26 import org.springframework.transaction.annotation.Transactional;
26 27  
27 28 import javax.annotation.Resource;
28   -import java.util.ArrayList;
29   -import java.util.List;
30   -import java.util.Map;
31   -import java.util.Set;
  29 +import java.util.*;
32 30 import java.util.function.BiPredicate;
33 31 import java.util.stream.Collectors;
34 32  
... ... @@ -129,6 +127,16 @@ public class CodegenServiceImpl implements CodegenService {
129 127 if (codegenTableMapper.selectById(updateReqVO.getTable().getId()) == null) {
130 128 throw exception(CODEGEN_TABLE_NOT_EXISTS);
131 129 }
  130 + // 校验主表字段存在
  131 + if (Objects.equals(updateReqVO.getTable().getTemplateType(), CodegenTemplateTypeEnum.SUB.getType())) {
  132 + if (codegenTableMapper.selectById(updateReqVO.getTable().getMasterTableId()) == null) {
  133 + throw exception(CODEGEN_MASTER_TABLE_NOT_EXISTS, updateReqVO.getTable().getMasterTableId());
  134 + }
  135 + if (CollUtil.findOne(updateReqVO.getColumns(), // 关联主表的字段不存在
  136 + column -> column.getId().equals(updateReqVO.getTable().getSubJoinColumnId())) == null) {
  137 + throw exception(CODEGEN_SUB_COLUMN_NOT_EXISTS, updateReqVO.getTable().getSubJoinColumnId());
  138 + }
  139 + }
132 140  
133 141 // 更新 table 表定义
134 142 CodegenTableDO updateTableObj = CodegenConvert.INSTANCE.convert(updateReqVO.getTable());
... ... @@ -209,6 +217,11 @@ public class CodegenServiceImpl implements CodegenService {
209 217 }
210 218  
211 219 @Override
  220 + public List<CodegenTableDO> getCodegenTableList(Long dataSourceConfigId) {
  221 + return codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId);
  222 + }
  223 +
  224 + @Override
212 225 public PageResult<CodegenTableDO> getCodegenTablePage(CodegenTablePageReqVO pageReqVO) {
213 226 return codegenTableMapper.selectPage(pageReqVO);
214 227 }
... ... @@ -235,14 +248,34 @@ public class CodegenServiceImpl implements CodegenService {
235 248 throw exception(CODEGEN_COLUMN_NOT_EXISTS);
236 249 }
237 250  
  251 + // 如果是主子表,则加载对应的子表信息
  252 + List<CodegenTableDO> subTables = null;
  253 + List<List<CodegenColumnDO>> subColumnsList = null;
  254 + if (CodegenTemplateTypeEnum.isMaster(table.getTemplateType())) {
  255 + // 校验子表存在
  256 + subTables = codegenTableMapper.selectListByTemplateTypeAndMasterTableId(
  257 + CodegenTemplateTypeEnum.SUB.getType(), tableId);
  258 + if (CollUtil.isEmpty(subTables)) {
  259 + throw exception(CODEGEN_MASTER_GENERATION_FAIL_NO_SUB_TABLE);
  260 + }
  261 + // 校验子表的关联字段存在
  262 + subColumnsList = new ArrayList<>();
  263 + for (CodegenTableDO subTable : subTables) {
  264 + List<CodegenColumnDO> subColumns = codegenColumnMapper.selectListByTableId(subTable.getId());
  265 + if (CollUtil.findOne(subColumns, column -> column.getId().equals(subTable.getSubJoinColumnId())) == null) {
  266 + throw exception(CODEGEN_SUB_COLUMN_NOT_EXISTS, subTable.getId());
  267 + }
  268 + subColumnsList.add(subColumns);
  269 + }
  270 + }
  271 +
238 272 // 执行生成
239   - return codegenEngine.execute(table, columns);
  273 + return codegenEngine.execute(table, columns, subTables, subColumnsList);
240 274 }
241 275  
242 276 @Override
243 277 public List<DatabaseTableRespVO> getDatabaseTableList(Long dataSourceConfigId, String name, String comment) {
244 278 List<TableInfo> tables = databaseTableService.getTableList(dataSourceConfigId, name, comment);
245   - // 移除已经生成的表
246 279 // 移除在 Codegen 中,已经存在的
247 280 Set<String> existsTables = CollectionUtils.convertSet(
248 281 codegenTableMapper.selectListByDataSourceConfigId(dataSourceConfigId), CodegenTableDO::getTableName);
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenBuilder.java
... ... @@ -15,6 +15,7 @@ import com.baomidou.mybatisplus.generator.config.po.TableInfo;
15 15 import com.google.common.collect.Sets;
16 16 import org.springframework.stereotype.Component;
17 17  
  18 +import java.time.LocalDateTime;
18 19 import java.util.*;
19 20  
20 21 import static cn.hutool.core.text.CharSequenceUtil.*;
... ... @@ -49,8 +50,8 @@ public class CodegenBuilder {
49 50 .put("status", CodegenColumnHtmlTypeEnum.RADIO)
50 51 .put("sex", CodegenColumnHtmlTypeEnum.RADIO)
51 52 .put("type", CodegenColumnHtmlTypeEnum.SELECT)
52   - .put("image", CodegenColumnHtmlTypeEnum.UPLOAD_IMAGE)
53   - .put("file", CodegenColumnHtmlTypeEnum.UPLOAD_FILE)
  53 + .put("image", CodegenColumnHtmlTypeEnum.IMAGE_UPLOAD)
  54 + .put("file", CodegenColumnHtmlTypeEnum.FILE_UPLOAD)
54 55 .put("content", CodegenColumnHtmlTypeEnum.EDITOR)
55 56 .put("description", CodegenColumnHtmlTypeEnum.EDITOR)
56 57 .put("demo", CodegenColumnHtmlTypeEnum.EDITOR)
... ... @@ -118,7 +119,7 @@ public class CodegenBuilder {
118 119 table.setClassName(upperFirst(toCamelCase(subAfter(tableName, '_', false))));
119 120 // 去除结尾的表,作为类描述
120 121 table.setClassComment(StrUtil.removeSuffixIgnoreCase(table.getTableComment(), "表"));
121   - table.setTemplateType(CodegenTemplateTypeEnum.CRUD.getType());
  122 + table.setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
122 123 }
123 124  
124 125 public List<CodegenColumnDO> buildColumns(Long tableId, List<TableField> tableFields) {
... ... @@ -127,6 +128,10 @@ public class CodegenBuilder {
127 128 for (CodegenColumnDO column : columns) {
128 129 column.setTableId(tableId);
129 130 column.setOrdinalPosition(index++);
  131 + // 特殊处理:Byte => Integer
  132 + if (Byte.class.getSimpleName().equals(column.getJavaType())) {
  133 + column.setJavaType(Integer.class.getSimpleName());
  134 + }
130 135 // 初始化 Column 列的默认字段
131 136 processColumnOperation(column); // 处理 CRUD 相关的字段的默认值
132 137 processColumnUI(column); // 处理 UI 相关的字段的默认值
... ... @@ -162,10 +167,13 @@ public class CodegenBuilder {
162 167 .filter(entry -> StrUtil.endWithIgnoreCase(column.getJavaField(), entry.getKey()))
163 168 .findFirst().ifPresent(entry -> column.setHtmlType(entry.getValue().getType()));
164 169 // 如果是 Boolean 类型时,设置为 radio 类型.
165   - // 其它类型,因为字段名可以相对保障,所以不进行处理。例如说 date 对应 datetime 类型.
166 170 if (Boolean.class.getSimpleName().equals(column.getJavaType())) {
167 171 column.setHtmlType(CodegenColumnHtmlTypeEnum.RADIO.getType());
168 172 }
  173 + // 如果是 LocalDateTime 类型,则设置为 datetime 类型
  174 + if (LocalDateTime.class.getSimpleName().equals(column.getJavaType())) {
  175 + column.setHtmlType(CodegenColumnHtmlTypeEnum.DATETIME.getType());
  176 + }
169 177 // 兜底,设置默认为 input 类型
170 178 if (column.getHtmlType() == null) {
171 179 column.setHtmlType(CodegenColumnHtmlTypeEnum.INPUT.getType());
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
1 1 package cn.iocoder.yudao.module.infra.service.codegen.inner;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.core.util.ObjectUtil;
4 6 import cn.hutool.core.util.StrUtil;
5 7 import cn.hutool.extra.template.TemplateConfig;
6 8 import cn.hutool.extra.template.TemplateEngine;
... ... @@ -12,7 +14,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
12 14 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
13 15 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
14 16 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
  17 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
15 18 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  19 +import cn.iocoder.yudao.framework.common.util.string.StrUtils;
16 20 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
17 21 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
18 22 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
... ... @@ -25,7 +29,9 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
25 29 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
26 30 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
27 31 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  32 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
28 33 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
  34 +import com.google.common.annotations.VisibleForTesting;
29 35 import com.google.common.collect.ImmutableTable;
30 36 import com.google.common.collect.Maps;
31 37 import com.google.common.collect.Table;
... ... @@ -33,10 +39,7 @@ import org.springframework.stereotype.Component;
33 39  
34 40 import javax.annotation.PostConstruct;
35 41 import javax.annotation.Resource;
36   -import java.util.HashMap;
37   -import java.util.LinkedHashMap;
38   -import java.util.List;
39   -import java.util.Map;
  42 +import java.util.*;
40 43  
41 44 import static cn.hutool.core.map.MapUtil.getStr;
42 45 import static cn.hutool.core.text.CharSequenceUtil.*;
... ... @@ -60,20 +63,19 @@ public class CodegenEngine {
60 63 */
61 64 private static final Map<String, String> SERVER_TEMPLATES = MapUtil.<String, String>builder(new LinkedHashMap<>()) // 有序
62 65 // Java module-biz Main
63   - .put(javaTemplatePath("controller/vo/baseVO"), javaModuleImplVOFilePath("BaseVO"))
64   - .put(javaTemplatePath("controller/vo/createReqVO"), javaModuleImplVOFilePath("CreateReqVO"))
65 66 .put(javaTemplatePath("controller/vo/pageReqVO"), javaModuleImplVOFilePath("PageReqVO"))
  67 + .put(javaTemplatePath("controller/vo/listReqVO"), javaModuleImplVOFilePath("ListReqVO"))
66 68 .put(javaTemplatePath("controller/vo/respVO"), javaModuleImplVOFilePath("RespVO"))
67   - .put(javaTemplatePath("controller/vo/updateReqVO"), javaModuleImplVOFilePath("UpdateReqVO"))
68   - .put(javaTemplatePath("controller/vo/exportReqVO"), javaModuleImplVOFilePath("ExportReqVO"))
69   - .put(javaTemplatePath("controller/vo/excelVO"), javaModuleImplVOFilePath("ExcelVO"))
  69 + .put(javaTemplatePath("controller/vo/saveReqVO"), javaModuleImplVOFilePath("SaveReqVO"))
70 70 .put(javaTemplatePath("controller/controller"), javaModuleImplControllerFilePath())
71   - .put(javaTemplatePath("convert/convert"),
72   - javaModuleImplMainFilePath("convert/${table.businessName}/${table.className}Convert"))
73 71 .put(javaTemplatePath("dal/do"),
74 72 javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${table.className}DO"))
  73 + .put(javaTemplatePath("dal/do_sub"), // 特殊:主子表专属逻辑
  74 + javaModuleImplMainFilePath("dal/dataobject/${table.businessName}/${subTable.className}DO"))
75 75 .put(javaTemplatePath("dal/mapper"),
76 76 javaModuleImplMainFilePath("dal/mysql/${table.businessName}/${table.className}Mapper"))
  77 + .put(javaTemplatePath("dal/mapper_sub"), // 特殊:主子表专属逻辑
  78 + javaModuleImplMainFilePath("dal/mysql/${table.businessName}/${subTable.className}Mapper"))
77 79 .put(javaTemplatePath("dal/mapper.xml"), mapperXmlFilePath())
78 80 .put(javaTemplatePath("service/serviceImpl"),
79 81 javaModuleImplMainFilePath("service/${table.businessName}/${table.className}ServiceImpl"))
... ... @@ -99,34 +101,44 @@ public class CodegenEngine {
99 101 private static final Table<Integer, String, String> FRONT_TEMPLATES = ImmutableTable.<Integer, String, String>builder()
100 102 // Vue2 标准模版
101 103 .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("views/index.vue"),
102   - vueFilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
  104 + vueFilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
103 105 .put(CodegenFrontTypeEnum.VUE2.getType(), vueTemplatePath("api/api.js"),
104 106 vueFilePath("api/${table.moduleName}/${classNameVar}.js"))
105 107 // Vue3 标准模版
106 108 .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/index.vue"),
107   - vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
  109 + vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
108 110 .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/form.vue"),
109   - vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Form.vue"))
  111 + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue"))
  112 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑
  113 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue"))
  114 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑
  115 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue"))
  116 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_erp.vue"), // 特殊:主子表专属逻辑
  117 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}Form.vue"))
  118 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_inner.vue"), // 特殊:主子表专属逻辑
  119 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue"))
  120 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_erp.vue"), // 特殊:主子表专属逻辑
  121 + vue3FilePath("views/${table.moduleName}/${table.businessName}/components/${subSimpleClassName}List.vue"))
110 122 .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("api/api.ts"),
111   - vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts"))
  123 + vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
112 124 // Vue3 Schema 模版
113 125 .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/data.ts"),
114   - vue3FilePath("views/${table.moduleName}/${classNameVar}/${classNameVar}.data.ts"))
  126 + vue3FilePath("views/${table.moduleName}/${table.businessName}/${classNameVar}.data.ts"))
115 127 .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/index.vue"),
116   - vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
  128 + vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
117 129 .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/form.vue"),
118   - vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Form.vue"))
  130 + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Form.vue"))
119 131 .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("api/api.ts"),
120   - vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts"))
  132 + vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
121 133 // Vue3 vben 模版
122 134 .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/data.ts"),
123   - vue3FilePath("views/${table.moduleName}/${classNameVar}/${classNameVar}.data.ts"))
  135 + vue3FilePath("views/${table.moduleName}/${table.businessName}/${classNameVar}.data.ts"))
124 136 .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/index.vue"),
125   - vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
  137 + vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
126 138 .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("views/form.vue"),
127   - vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Modal.vue"))
  139 + vue3FilePath("views/${table.moduleName}/${table.businessName}/${simpleClassName}Modal.vue"))
128 140 .put(CodegenFrontTypeEnum.VUE3_VBEN.getType(), vue3VbenTemplatePath("api/api.ts"),
129   - vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts"))
  141 + vue3FilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
130 142 .build();
131 143  
132 144 @Resource
... ... @@ -149,7 +161,8 @@ public class CodegenEngine {
149 161 }
150 162  
151 163 @PostConstruct
152   - private void initGlobalBindingMap() {
  164 + @VisibleForTesting
  165 + void initGlobalBindingMap() {
153 166 // 全局配置
154 167 globalBindingMap.put("basePackage", codegenProperties.getBasePackage());
155 168 globalBindingMap.put("baseFrameworkPackage", codegenProperties.getBasePackage()
... ... @@ -174,9 +187,122 @@ public class CodegenEngine {
174 187 globalBindingMap.put("DictConvertClassName", DictConvert.class.getName());
175 188 globalBindingMap.put("OperateLogClassName", OperateLog.class.getName());
176 189 globalBindingMap.put("OperateTypeEnumClassName", OperateTypeEnum.class.getName());
  190 + globalBindingMap.put("BeanUtils", BeanUtils.class.getName());
177 191 }
178 192  
179   - public Map<String, String> execute(CodegenTableDO table, List<CodegenColumnDO> columns) {
  193 + /**
  194 + * 生成代码
  195 + *
  196 + * @param table 表定义
  197 + * @param columns table 的字段定义数组
  198 + * @param subTables 子表数组,当且仅当主子表时使用
  199 + * @param subColumnsList subTables 的字段定义数组
  200 + * @return 生成的代码,key 是路径,value 是对应代码
  201 + */
  202 + public Map<String, String> execute(CodegenTableDO table, List<CodegenColumnDO> columns,
  203 + List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
  204 + // 1.1 初始化 bindMap 上下文
  205 + Map<String, Object> bindingMap = initBindingMap(table, columns, subTables, subColumnsList);
  206 + // 1.2 获得模版
  207 + Map<String, String> templates = getTemplates(table.getFrontType());
  208 +
  209 + // 2. 执行生成
  210 + Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(templates.size()); // 有序
  211 + templates.forEach((vmPath, filePath) -> {
  212 + // 2.1 特殊:主子表专属逻辑
  213 + if (isSubTemplate(vmPath)) {
  214 + generateSubCode(table, subTables, result, vmPath, filePath, bindingMap);
  215 + return;
  216 + // 2.2 特殊:树表专属逻辑
  217 + } else if (isPageReqVOTemplate(vmPath)) {
  218 + // 减少多余的类生成,例如说 PageVO.java 类
  219 + if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) {
  220 + return;
  221 + }
  222 + } else if (isListReqVOTemplate(vmPath)) {
  223 + // 减少多余的类生成,例如说 ListVO.java 类
  224 + if (!CodegenTemplateTypeEnum.isTree(table.getTemplateType())) {
  225 + return;
  226 + }
  227 + }
  228 + // 2.3 默认生成
  229 + generateCode(result, vmPath, filePath, bindingMap);
  230 + });
  231 + return result;
  232 + }
  233 +
  234 + private void generateCode(Map<String, String> result, String vmPath,
  235 + String filePath, Map<String, Object> bindingMap) {
  236 + filePath = formatFilePath(filePath, bindingMap);
  237 + String content = templateEngine.getTemplate(vmPath).render(bindingMap);
  238 + // 格式化代码
  239 + content = prettyCode(content);
  240 + result.put(filePath, content);
  241 + }
  242 +
  243 + private void generateSubCode(CodegenTableDO table, List<CodegenTableDO> subTables,
  244 + Map<String, String> result, String vmPath,
  245 + String filePath, Map<String, Object> bindingMap) {
  246 + // 没有子表,所以不生成
  247 + if (CollUtil.isEmpty(subTables)) {
  248 + return;
  249 + }
  250 + // 主子表的模式匹配。目的:过滤掉个性化的模版
  251 + if (vmPath.contains("_normal")
  252 + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_NORMAL.getType())) {
  253 + return;
  254 + }
  255 + if (vmPath.contains("_erp")
  256 + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_ERP.getType())) {
  257 + return;
  258 + }
  259 + if (vmPath.contains("_inner")
  260 + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_INNER.getType())) {
  261 + return;
  262 + }
  263 +
  264 + // 逐个生成
  265 + for (int i = 0; i < subTables.size(); i++) {
  266 + bindingMap.put("subIndex", i);
  267 + generateCode(result, vmPath, filePath, bindingMap);
  268 + }
  269 + bindingMap.remove("subIndex");
  270 + }
  271 +
  272 + /**
  273 + * 格式化生成后的代码
  274 + *
  275 + * 因为尽量让 vm 模版简单,所以统一的处理都在这个方法。
  276 + * 如果不处理,Vue 的 Pretty 格式校验可能会报错
  277 + *
  278 + * @param content 格式化前的代码
  279 + * @return 格式化后的代码
  280 + */
  281 + private String prettyCode(String content) {
  282 + // Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错
  283 + content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
  284 + // Vue 界面:去除多的 dateFormatter,只有一个的情况下,说明没使用到
  285 + if (StrUtil.count(content, "dateFormatter") == 1) {
  286 + content = StrUtils.removeLineContains(content, "dateFormatter");
  287 + }
  288 + // Vue 界面:去除多的 dict 相关,只有一个的情况下,说明没使用到
  289 + if (StrUtil.count(content, "getIntDictOptions") == 1) {
  290 + content = content.replace("getIntDictOptions, ", "");
  291 + }
  292 + if (StrUtil.count(content, "getStrDictOptions") == 1) {
  293 + content = content.replace("getStrDictOptions, ", "");
  294 + }
  295 + if (StrUtil.count(content, "getBoolDictOptions") == 1) {
  296 + content = content.replace("getBoolDictOptions, ", "");
  297 + }
  298 + if (StrUtil.count(content, "DICT_TYPE.") == 0) {
  299 + content = StrUtils.removeLineContains(content, "DICT_TYPE");
  300 + }
  301 + return content;
  302 + }
  303 +
  304 + private Map<String, Object> initBindingMap(CodegenTableDO table, List<CodegenColumnDO> columns,
  305 + List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
180 306 // 创建 bindingMap
181 307 Map<String, Object> bindingMap = new HashMap<>(globalBindingMap);
182 308 bindingMap.put("table", table);
... ... @@ -196,17 +322,54 @@ public class CodegenEngine {
196 322 // permission 前缀
197 323 bindingMap.put("permissionPrefix", table.getModuleName() + ":" + simpleClassNameStrikeCase);
198 324  
199   - // 执行生成
200   - Map<String, String> templates = getTemplates(table.getFrontType());
201   - Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(templates.size()); // 有序
202   - templates.forEach((vmPath, filePath) -> {
203   - filePath = formatFilePath(filePath, bindingMap);
204   - String content = templateEngine.getTemplate(vmPath).render(bindingMap);
205   - // 去除字段后面多余的 , 逗号
206   - content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
207   - result.put(filePath, content);
208   - });
209   - return result;
  325 + // 特殊:树表专属逻辑
  326 + if (CodegenTemplateTypeEnum.isTree(table.getTemplateType())) {
  327 + CodegenColumnDO treeParentColumn = CollUtil.findOne(columns,
  328 + column -> Objects.equals(column.getId(), table.getTreeParentColumnId()));
  329 + bindingMap.put("treeParentColumn", treeParentColumn);
  330 + bindingMap.put("treeParentColumn_javaField_underlineCase", toUnderlineCase(treeParentColumn.getJavaField()));
  331 + CodegenColumnDO treeNameColumn = CollUtil.findOne(columns,
  332 + column -> Objects.equals(column.getId(), table.getTreeNameColumnId()));
  333 + bindingMap.put("treeNameColumn", treeNameColumn);
  334 + bindingMap.put("treeNameColumn_javaField_underlineCase", toUnderlineCase(treeNameColumn.getJavaField()));
  335 + }
  336 +
  337 + // 特殊:主子表专属逻辑
  338 + if (CollUtil.isNotEmpty(subTables)) {
  339 + // 创建 bindingMap
  340 + bindingMap.put("subTables", subTables);
  341 + bindingMap.put("subColumnsList", subColumnsList);
  342 + List<CodegenColumnDO> subPrimaryColumns = new ArrayList<>();
  343 + List<CodegenColumnDO> subJoinColumns = new ArrayList<>();
  344 + List<String> subJoinColumnStrikeCases = new ArrayList<>();
  345 + List<String> subSimpleClassNames = new ArrayList<>();
  346 + List<String> subClassNameVars = new ArrayList<>();
  347 + List<String> simpleClassNameUnderlineCases = new ArrayList<>();
  348 + List<String> subSimpleClassNameStrikeCases = new ArrayList<>();
  349 + for (int i = 0; i < subTables.size(); i++) {
  350 + CodegenTableDO subTable = subTables.get(i);
  351 + List<CodegenColumnDO> subColumns = subColumnsList.get(i);
  352 + subPrimaryColumns.add(CollectionUtils.findFirst(subColumns, CodegenColumnDO::getPrimaryKey)); //
  353 + CodegenColumnDO subColumn = CollectionUtils.findFirst(subColumns, // 关联的字段
  354 + column -> Objects.equals(column.getId(), subTable.getSubJoinColumnId()));
  355 + subJoinColumns.add(subColumn);
  356 + subJoinColumnStrikeCases.add(toSymbolCase(subColumn.getJavaField(), '-')); // 将 DictType 转换成 dict-type
  357 + // className 相关
  358 + String subSimpleClassName = removePrefix(subTable.getClassName(), upperFirst(subTable.getModuleName()));
  359 + subSimpleClassNames.add(subSimpleClassName);
  360 + simpleClassNameUnderlineCases.add(toUnderlineCase(subSimpleClassName)); // 将 DictType 转换成 dict_type
  361 + subClassNameVars.add(lowerFirst(subSimpleClassName)); // 将 DictType 转换成 dictType,用于变量
  362 + subSimpleClassNameStrikeCases.add(toSymbolCase(subSimpleClassName, '-')); // 将 DictType 转换成 dict-type
  363 + }
  364 + bindingMap.put("subPrimaryColumns", subPrimaryColumns);
  365 + bindingMap.put("subJoinColumns", subJoinColumns);
  366 + bindingMap.put("subJoinColumn_strikeCases", subJoinColumnStrikeCases);
  367 + bindingMap.put("subSimpleClassNames", subSimpleClassNames);
  368 + bindingMap.put("simpleClassNameUnderlineCases", simpleClassNameUnderlineCases);
  369 + bindingMap.put("subClassNameVars", subClassNameVars);
  370 + bindingMap.put("subSimpleClassName_strikeCases", subSimpleClassNameStrikeCases);
  371 + }
  372 + return bindingMap;
210 373 }
211 374  
212 375 private Map<String, String> getTemplates(Integer frontType) {
... ... @@ -216,6 +379,7 @@ public class CodegenEngine {
216 379 return templates;
217 380 }
218 381  
  382 + @SuppressWarnings("unchecked")
219 383 private String formatFilePath(String filePath, Map<String, Object> bindingMap) {
220 384 filePath = StrUtil.replace(filePath, "${basePackage}",
221 385 getStr(bindingMap, "basePackage").replaceAll("\\.", "/"));
... ... @@ -232,6 +396,16 @@ public class CodegenEngine {
232 396 filePath = StrUtil.replace(filePath, "${table.moduleName}", table.getModuleName());
233 397 filePath = StrUtil.replace(filePath, "${table.businessName}", table.getBusinessName());
234 398 filePath = StrUtil.replace(filePath, "${table.className}", table.getClassName());
  399 + // 特殊:主子表专属逻辑
  400 + Integer subIndex = (Integer) bindingMap.get("subIndex");
  401 + if (subIndex != null) {
  402 + CodegenTableDO subTable = ((List<CodegenTableDO>) bindingMap.get("subTables")).get(subIndex);
  403 + filePath = StrUtil.replace(filePath, "${subTable.moduleName}", subTable.getModuleName());
  404 + filePath = StrUtil.replace(filePath, "${subTable.businessName}", subTable.getBusinessName());
  405 + filePath = StrUtil.replace(filePath, "${subTable.className}", subTable.getClassName());
  406 + filePath = StrUtil.replace(filePath, "${subSimpleClassName}",
  407 + ((List<String>) bindingMap.get("subSimpleClassNames")).get(subIndex));
  408 + }
235 409 return filePath;
236 410 }
237 411  
... ... @@ -298,4 +472,17 @@ public class CodegenEngine {
298 472 private static String vue3VbenTemplatePath(String path) {
299 473 return "codegen/vue3_vben/" + path + ".vm";
300 474 }
  475 +
  476 + private static boolean isSubTemplate(String path) {
  477 + return path.contains("_sub");
  478 + }
  479 +
  480 + private static boolean isPageReqVOTemplate(String path) {
  481 + return path.contains("pageReqVO");
  482 + }
  483 +
  484 + private static boolean isListReqVOTemplate(String path) {
  485 + return path.contains("listReqVO");
  486 + }
  487 +
301 488 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo01/Demo01ContactService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo.demo01;
  2 +
  3 +import javax.validation.*;
  4 +
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO;
  6 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01.Demo01ContactDO;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +
  10 +/**
  11 + * 示例联系人 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface Demo01ContactService {
  16 +
  17 + /**
  18 + * 创建示例联系人
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createDemo01Contact(@Valid Demo01ContactSaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 更新示例联系人
  27 + *
  28 + * @param updateReqVO 更新信息
  29 + */
  30 + void updateDemo01Contact(@Valid Demo01ContactSaveReqVO updateReqVO);
  31 +
  32 + /**
  33 + * 删除示例联系人
  34 + *
  35 + * @param id 编号
  36 + */
  37 + void deleteDemo01Contact(Long id);
  38 +
  39 + /**
  40 + * 获得示例联系人
  41 + *
  42 + * @param id 编号
  43 + * @return 示例联系人
  44 + */
  45 + Demo01ContactDO getDemo01Contact(Long id);
  46 +
  47 + /**
  48 + * 获得示例联系人分页
  49 + *
  50 + * @param pageReqVO 分页查询
  51 + * @return 示例联系人分页
  52 + */
  53 + PageResult<Demo01ContactDO> getDemo01ContactPage(Demo01ContactPageReqVO pageReqVO);
  54 +
  55 +}
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo01/Demo01ContactServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo.demo01;
  2 +
  3 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactPageReqVO;
  4 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo01.vo.Demo01ContactSaveReqVO;
  5 +import org.springframework.stereotype.Service;
  6 +import javax.annotation.Resource;
  7 +import org.springframework.validation.annotation.Validated;
  8 +
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo01.Demo01ContactDO;
  10 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  11 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  12 +
  13 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo01.Demo01ContactMapper;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  16 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  17 +
  18 +/**
  19 + * 示例联系人 Service 实现类
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Service
  24 +@Validated
  25 +public class Demo01ContactServiceImpl implements Demo01ContactService {
  26 +
  27 + @Resource
  28 + private Demo01ContactMapper demo01ContactMapper;
  29 +
  30 + @Override
  31 + public Long createDemo01Contact(Demo01ContactSaveReqVO createReqVO) {
  32 + // 插入
  33 + Demo01ContactDO demo01Contact = BeanUtils.toBean(createReqVO, Demo01ContactDO.class);
  34 + demo01ContactMapper.insert(demo01Contact);
  35 + // 返回
  36 + return demo01Contact.getId();
  37 + }
  38 +
  39 + @Override
  40 + public void updateDemo01Contact(Demo01ContactSaveReqVO updateReqVO) {
  41 + // 校验存在
  42 + validateDemo01ContactExists(updateReqVO.getId());
  43 + // 更新
  44 + Demo01ContactDO updateObj = BeanUtils.toBean(updateReqVO, Demo01ContactDO.class);
  45 + demo01ContactMapper.updateById(updateObj);
  46 + }
  47 +
  48 + @Override
  49 + public void deleteDemo01Contact(Long id) {
  50 + // 校验存在
  51 + validateDemo01ContactExists(id);
  52 + // 删除
  53 + demo01ContactMapper.deleteById(id);
  54 + }
  55 +
  56 + private void validateDemo01ContactExists(Long id) {
  57 + if (demo01ContactMapper.selectById(id) == null) {
  58 + throw exception(DEMO01_CONTACT_NOT_EXISTS);
  59 + }
  60 + }
  61 +
  62 + @Override
  63 + public Demo01ContactDO getDemo01Contact(Long id) {
  64 + return demo01ContactMapper.selectById(id);
  65 + }
  66 +
  67 + @Override
  68 + public PageResult<Demo01ContactDO> getDemo01ContactPage(Demo01ContactPageReqVO pageReqVO) {
  69 + return demo01ContactMapper.selectPage(pageReqVO);
  70 + }
  71 +
  72 +}
0 73 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo02/Demo02CategoryService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo.demo02;
  2 +
  3 +import java.util.*;
  4 +import javax.validation.*;
  5 +
  6 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02.Demo02CategoryDO;
  9 +
  10 +/**
  11 + * 示例分类 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface Demo02CategoryService {
  16 +
  17 + /**
  18 + * 创建示例分类
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createDemo02Category(@Valid Demo02CategorySaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 更新示例分类
  27 + *
  28 + * @param updateReqVO 更新信息
  29 + */
  30 + void updateDemo02Category(@Valid Demo02CategorySaveReqVO updateReqVO);
  31 +
  32 + /**
  33 + * 删除示例分类
  34 + *
  35 + * @param id 编号
  36 + */
  37 + void deleteDemo02Category(Long id);
  38 +
  39 + /**
  40 + * 获得示例分类
  41 + *
  42 + * @param id 编号
  43 + * @return 示例分类
  44 + */
  45 + Demo02CategoryDO getDemo02Category(Long id);
  46 +
  47 + /**
  48 + * 获得示例分类列表
  49 + *
  50 + * @param listReqVO 查询条件
  51 + * @return 示例分类列表
  52 + */
  53 + List<Demo02CategoryDO> getDemo02CategoryList(Demo02CategoryListReqVO listReqVO);
  54 +
  55 +}
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo02/Demo02CategoryServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo.demo02;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  4 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategoryListReqVO;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo02.vo.Demo02CategorySaveReqVO;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo02.Demo02CategoryDO;
  7 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo02.Demo02CategoryMapper;
  8 +import org.springframework.stereotype.Service;
  9 +import org.springframework.validation.annotation.Validated;
  10 +
  11 +import javax.annotation.Resource;
  12 +import java.util.List;
  13 +import java.util.Objects;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  16 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  17 +
  18 +/**
  19 + * 示例分类 Service 实现类
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Service
  24 +@Validated
  25 +public class Demo02CategoryServiceImpl implements Demo02CategoryService {
  26 +
  27 + @Resource
  28 + private Demo02CategoryMapper demo02CategoryMapper;
  29 +
  30 + @Override
  31 + public Long createDemo02Category(Demo02CategorySaveReqVO createReqVO) {
  32 + // 校验父级编号的有效性
  33 + validateParentDemo02Category(null, createReqVO.getParentId());
  34 + // 校验名字的唯一性
  35 + validateDemo02CategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
  36 +
  37 + // 插入
  38 + Demo02CategoryDO demo02Category = BeanUtils.toBean(createReqVO, Demo02CategoryDO.class);
  39 + demo02CategoryMapper.insert(demo02Category);
  40 + // 返回
  41 + return demo02Category.getId();
  42 + }
  43 +
  44 + @Override
  45 + public void updateDemo02Category(Demo02CategorySaveReqVO updateReqVO) {
  46 + // 校验存在
  47 + validateDemo02CategoryExists(updateReqVO.getId());
  48 + // 校验父级编号的有效性
  49 + validateParentDemo02Category(updateReqVO.getId(), updateReqVO.getParentId());
  50 + // 校验名字的唯一性
  51 + validateDemo02CategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
  52 +
  53 + // 更新
  54 + Demo02CategoryDO updateObj = BeanUtils.toBean(updateReqVO, Demo02CategoryDO.class);
  55 + demo02CategoryMapper.updateById(updateObj);
  56 + }
  57 +
  58 + @Override
  59 + public void deleteDemo02Category(Long id) {
  60 + // 校验存在
  61 + validateDemo02CategoryExists(id);
  62 + // 校验是否有子示例分类
  63 + if (demo02CategoryMapper.selectCountByParentId(id) > 0) {
  64 + throw exception(DEMO02_CATEGORY_EXITS_CHILDREN);
  65 + }
  66 + // 删除
  67 + demo02CategoryMapper.deleteById(id);
  68 + }
  69 +
  70 + private void validateDemo02CategoryExists(Long id) {
  71 + if (demo02CategoryMapper.selectById(id) == null) {
  72 + throw exception(DEMO02_CATEGORY_NOT_EXISTS);
  73 + }
  74 + }
  75 +
  76 + private void validateParentDemo02Category(Long id, Long parentId) {
  77 + if (parentId == null || Demo02CategoryDO.PARENT_ID_ROOT.equals(parentId)) {
  78 + return;
  79 + }
  80 + // 1. 不能设置自己为父示例分类
  81 + if (Objects.equals(id, parentId)) {
  82 + throw exception(DEMO02_CATEGORY_PARENT_ERROR);
  83 + }
  84 + // 2. 父示例分类不存在
  85 + Demo02CategoryDO parentDemo02Category = demo02CategoryMapper.selectById(parentId);
  86 + if (parentDemo02Category == null) {
  87 + throw exception(DEMO02_CATEGORY_PARENT_NOT_EXITS);
  88 + }
  89 + // 3. 递归校验父示例分类,如果父示例分类是自己的子示例分类,则报错,避免形成环路
  90 + if (id == null) { // id 为空,说明新增,不需要考虑环路
  91 + return;
  92 + }
  93 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  94 + // 3.1 校验环路
  95 + parentId = parentDemo02Category.getParentId();
  96 + if (Objects.equals(id, parentId)) {
  97 + throw exception(DEMO02_CATEGORY_PARENT_IS_CHILD);
  98 + }
  99 + // 3.2 继续递归下一级父示例分类
  100 + if (parentId == null || Demo02CategoryDO.PARENT_ID_ROOT.equals(parentId)) {
  101 + break;
  102 + }
  103 + parentDemo02Category = demo02CategoryMapper.selectById(parentId);
  104 + if (parentDemo02Category == null) {
  105 + break;
  106 + }
  107 + }
  108 + }
  109 +
  110 + private void validateDemo02CategoryNameUnique(Long id, Long parentId, String name) {
  111 + Demo02CategoryDO demo02Category = demo02CategoryMapper.selectByParentIdAndName(parentId, name);
  112 + if (demo02Category == null) {
  113 + return;
  114 + }
  115 + // 如果 id 为空,说明不用比较是否为相同 id 的示例分类
  116 + if (id == null) {
  117 + throw exception(DEMO02_CATEGORY_NAME_DUPLICATE);
  118 + }
  119 + if (!Objects.equals(demo02Category.getId(), id)) {
  120 + throw exception(DEMO02_CATEGORY_NAME_DUPLICATE);
  121 + }
  122 + }
  123 +
  124 + @Override
  125 + public Demo02CategoryDO getDemo02Category(Long id) {
  126 + return demo02CategoryMapper.selectById(id);
  127 + }
  128 +
  129 + @Override
  130 + public List<Demo02CategoryDO> getDemo02CategoryList(Demo02CategoryListReqVO listReqVO) {
  131 + return demo02CategoryMapper.selectList(listReqVO);
  132 + }
  133 +
  134 +}
0 135 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo03/Demo03StudentService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo.demo03;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO;
  6 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03StudentDO;
  10 +
  11 +import javax.validation.Valid;
  12 +import java.util.List;
  13 +
  14 +/**
  15 + * 学生 Service 接口
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +public interface Demo03StudentService {
  20 +
  21 + /**
  22 + * 创建学生
  23 + *
  24 + * @param createReqVO 创建信息
  25 + * @return 编号
  26 + */
  27 + Long createDemo03Student(@Valid Demo03StudentSaveReqVO createReqVO);
  28 +
  29 + /**
  30 + * 更新学生
  31 + *
  32 + * @param updateReqVO 更新信息
  33 + */
  34 + void updateDemo03Student(@Valid Demo03StudentSaveReqVO updateReqVO);
  35 +
  36 + /**
  37 + * 删除学生
  38 + *
  39 + * @param id 编号
  40 + */
  41 + void deleteDemo03Student(Long id);
  42 +
  43 + /**
  44 + * 获得学生
  45 + *
  46 + * @param id 编号
  47 + * @return 学生
  48 + */
  49 + Demo03StudentDO getDemo03Student(Long id);
  50 +
  51 + /**
  52 + * 获得学生分页
  53 + *
  54 + * @param pageReqVO 分页查询
  55 + * @return 学生分页
  56 + */
  57 + PageResult<Demo03StudentDO> getDemo03StudentPage(Demo03StudentPageReqVO pageReqVO);
  58 +
  59 +
  60 + // ==================== 子表(学生课程) ====================
  61 +
  62 + /**
  63 + * 获得学生课程列表
  64 + *
  65 + * @param studentId 学生编号
  66 + * @return 学生课程列表
  67 + */
  68 + List<Demo03CourseDO> getDemo03CourseListByStudentId(Long studentId);
  69 +
  70 + /**
  71 + * 获得学生课程分页
  72 + *
  73 + * @param pageReqVO 分页查询
  74 + * @param studentId 学生编号
  75 + * @return 学生课程分页
  76 + */
  77 + PageResult<Demo03CourseDO> getDemo03CoursePage(PageParam pageReqVO, Long studentId);
  78 +
  79 + /**
  80 + * 创建学生课程
  81 + *
  82 + * @param demo03Course 创建信息
  83 + * @return 编号
  84 + */
  85 + Long createDemo03Course(@Valid Demo03CourseDO demo03Course);
  86 +
  87 + /**
  88 + * 更新学生课程
  89 + *
  90 + * @param demo03Course 更新信息
  91 + */
  92 + void updateDemo03Course(@Valid Demo03CourseDO demo03Course);
  93 +
  94 + /**
  95 + * 删除学生课程
  96 + *
  97 + * @param id 编号
  98 + */
  99 + void deleteDemo03Course(Long id);
  100 +
  101 + /**
  102 + * 获得学生课程
  103 + *
  104 + * @param id 编号
  105 + * @return 学生课程
  106 + */
  107 + Demo03CourseDO getDemo03Course(Long id);
  108 +
  109 + // ==================== 子表(学生班级) ====================
  110 +
  111 + /**
  112 + * 获得学生班级
  113 + *
  114 + * @param studentId 学生编号
  115 + * @return 学生班级
  116 + */
  117 + Demo03GradeDO getDemo03GradeByStudentId(Long studentId);
  118 +
  119 + /**
  120 + * 获得学生班级分页
  121 + *
  122 + * @param pageReqVO 分页查询
  123 + * @param studentId 学生编号
  124 + * @return 学生班级分页
  125 + */
  126 + PageResult<Demo03GradeDO> getDemo03GradePage(PageParam pageReqVO, Long studentId);
  127 +
  128 + /**
  129 + * 创建学生班级
  130 + *
  131 + * @param demo03Grade 创建信息
  132 + * @return 编号
  133 + */
  134 + Long createDemo03Grade(@Valid Demo03GradeDO demo03Grade);
  135 +
  136 + /**
  137 + * 更新学生班级
  138 + *
  139 + * @param demo03Grade 更新信息
  140 + */
  141 + void updateDemo03Grade(@Valid Demo03GradeDO demo03Grade);
  142 +
  143 + /**
  144 + * 删除学生班级
  145 + *
  146 + * @param id 编号
  147 + */
  148 + void deleteDemo03Grade(Long id);
  149 +
  150 + /**
  151 + * 获得学生班级
  152 + *
  153 + * @param id 编号
  154 + * @return 学生班级
  155 + */
  156 + Demo03GradeDO getDemo03Grade(Long id);
  157 +
  158 +}
0 159 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/demo03/Demo03StudentServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo.demo03;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentPageReqVO;
  7 +import cn.iocoder.yudao.module.infra.controller.admin.demo.demo03.vo.Demo03StudentSaveReqVO;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03CourseDO;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03GradeDO;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.demo03.Demo03StudentDO;
  11 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03.Demo03CourseMapper;
  12 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03.Demo03GradeMapper;
  13 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.demo03.Demo03StudentMapper;
  14 +import org.springframework.stereotype.Service;
  15 +import org.springframework.transaction.annotation.Transactional;
  16 +import org.springframework.validation.annotation.Validated;
  17 +
  18 +import javax.annotation.Resource;
  19 +import java.util.List;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class Demo03StudentServiceImpl implements Demo03StudentService {
  32 +
  33 + @Resource
  34 + private Demo03StudentMapper demo03StudentMapper;
  35 + @Resource
  36 + private Demo03CourseMapper demo03CourseMapper;
  37 + @Resource
  38 + private Demo03GradeMapper demo03GradeMapper;
  39 +
  40 + @Override
  41 + @Transactional(rollbackFor = Exception.class)
  42 + public Long createDemo03Student(Demo03StudentSaveReqVO createReqVO) {
  43 + // 插入
  44 + Demo03StudentDO demo03Student = BeanUtils.toBean(createReqVO, Demo03StudentDO.class);
  45 + demo03StudentMapper.insert(demo03Student);
  46 +
  47 + // 插入子表
  48 + createDemo03CourseList(demo03Student.getId(), createReqVO.getDemo03Courses());
  49 + createDemo03Grade(demo03Student.getId(), createReqVO.getDemo03Grade());
  50 + // 返回
  51 + return demo03Student.getId();
  52 + }
  53 +
  54 + @Override
  55 + @Transactional(rollbackFor = Exception.class)
  56 + public void updateDemo03Student(Demo03StudentSaveReqVO updateReqVO) {
  57 + // 校验存在
  58 + validateDemo03StudentExists(updateReqVO.getId());
  59 + // 更新
  60 + Demo03StudentDO updateObj = BeanUtils.toBean(updateReqVO, Demo03StudentDO.class);
  61 + demo03StudentMapper.updateById(updateObj);
  62 +
  63 + // 更新子表
  64 + updateDemo03CourseList(updateReqVO.getId(), updateReqVO.getDemo03Courses());
  65 + updateDemo03Grade(updateReqVO.getId(), updateReqVO.getDemo03Grade());
  66 + }
  67 +
  68 + @Override
  69 + @Transactional(rollbackFor = Exception.class)
  70 + public void deleteDemo03Student(Long id) {
  71 + // 校验存在
  72 + validateDemo03StudentExists(id);
  73 + // 删除
  74 + demo03StudentMapper.deleteById(id);
  75 +
  76 + // 删除子表
  77 + deleteDemo03CourseByStudentId(id);
  78 + deleteDemo03GradeByStudentId(id);
  79 + }
  80 +
  81 + private void validateDemo03StudentExists(Long id) {
  82 + if (demo03StudentMapper.selectById(id) == null) {
  83 + throw exception(DEMO03_STUDENT_NOT_EXISTS);
  84 + }
  85 + }
  86 +
  87 + @Override
  88 + public Demo03StudentDO getDemo03Student(Long id) {
  89 + return demo03StudentMapper.selectById(id);
  90 + }
  91 +
  92 + @Override
  93 + public PageResult<Demo03StudentDO> getDemo03StudentPage(Demo03StudentPageReqVO pageReqVO) {
  94 + return demo03StudentMapper.selectPage(pageReqVO);
  95 + }
  96 +
  97 + // ==================== 子表(学生课程) ====================
  98 +
  99 + @Override
  100 + public List<Demo03CourseDO> getDemo03CourseListByStudentId(Long studentId) {
  101 + return demo03CourseMapper.selectListByStudentId(studentId);
  102 + }
  103 +
  104 + private void createDemo03CourseList(Long studentId, List<Demo03CourseDO> list) {
  105 + if (list != null) {
  106 + list.forEach(o -> o.setStudentId(studentId));
  107 + }
  108 + demo03CourseMapper.insertBatch(list);
  109 + }
  110 +
  111 + private void updateDemo03CourseList(Long studentId, List<Demo03CourseDO> list) {
  112 + deleteDemo03CourseByStudentId(studentId);
  113 + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新
  114 + createDemo03CourseList(studentId, list);
  115 + }
  116 +
  117 + private void deleteDemo03CourseByStudentId(Long studentId) {
  118 + demo03CourseMapper.deleteByStudentId(studentId);
  119 + }
  120 +
  121 + @Override
  122 + public PageResult<Demo03CourseDO> getDemo03CoursePage(PageParam pageReqVO, Long studentId) {
  123 + return demo03CourseMapper.selectPage(pageReqVO, studentId);
  124 + }
  125 +
  126 + @Override
  127 + public Long createDemo03Course(Demo03CourseDO demo03Course) {
  128 + demo03CourseMapper.insert(demo03Course);
  129 + return demo03Course.getId();
  130 + }
  131 +
  132 + @Override
  133 + public void updateDemo03Course(Demo03CourseDO demo03Course) {
  134 + demo03CourseMapper.updateById(demo03Course);
  135 + }
  136 +
  137 + @Override
  138 + public void deleteDemo03Course(Long id) {
  139 + demo03CourseMapper.deleteById(id);
  140 + }
  141 +
  142 + @Override
  143 + public Demo03CourseDO getDemo03Course(Long id) {
  144 + return demo03CourseMapper.selectById(id);
  145 + }
  146 +
  147 + // ==================== 子表(学生班级) ====================
  148 +
  149 + @Override
  150 + public Demo03GradeDO getDemo03GradeByStudentId(Long studentId) {
  151 + return demo03GradeMapper.selectByStudentId(studentId);
  152 + }
  153 +
  154 + private void createDemo03Grade(Long studentId, Demo03GradeDO demo03Grade) {
  155 + if (demo03Grade == null) {
  156 + return;
  157 + }
  158 + demo03Grade.setStudentId(studentId);
  159 + demo03GradeMapper.insert(demo03Grade);
  160 + }
  161 +
  162 + private void updateDemo03Grade(Long studentId, Demo03GradeDO demo03Grade) {
  163 + if (demo03Grade == null) {
  164 + return;
  165 + }
  166 + demo03Grade.setStudentId(studentId);
  167 + demo03Grade.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新
  168 + demo03GradeMapper.insertOrUpdate(demo03Grade);
  169 + }
  170 +
  171 + private void deleteDemo03GradeByStudentId(Long studentId) {
  172 + demo03GradeMapper.deleteByStudentId(studentId);
  173 + }
  174 +
  175 + @Override
  176 + public PageResult<Demo03GradeDO> getDemo03GradePage(PageParam pageReqVO, Long studentId) {
  177 + return demo03GradeMapper.selectPage(pageReqVO, studentId);
  178 + }
  179 +
  180 + @Override
  181 + public Long createDemo03Grade(Demo03GradeDO demo03Grade) {
  182 + // 校验是否已经存在
  183 + if (demo03GradeMapper.selectByStudentId(demo03Grade.getStudentId()) != null) {
  184 + throw exception(DEMO03_GRADE_EXISTS);
  185 + }
  186 + demo03GradeMapper.insert(demo03Grade);
  187 + return demo03Grade.getId();
  188 + }
  189 +
  190 + @Override
  191 + public void updateDemo03Grade(Demo03GradeDO demo03Grade) {
  192 + // 校验存在
  193 + validateDemo03GradeExists(demo03Grade.getId());
  194 + // 更新
  195 + demo03GradeMapper.updateById(demo03Grade);
  196 + }
  197 +
  198 + @Override
  199 + public void deleteDemo03Grade(Long id) {
  200 + // 校验存在
  201 + validateDemo03GradeExists(id);
  202 + // 删除
  203 + demo03GradeMapper.deleteById(id);
  204 + }
  205 +
  206 + @Override
  207 + public Demo03GradeDO getDemo03Grade(Long id) {
  208 + return demo03GradeMapper.selectById(id);
  209 + }
  210 +
  211 + private void validateDemo03GradeExists(Long id) {
  212 + if (demo03GradeMapper.selectById(id) == null) {
  213 + throw exception(DEMO03_GRADE_NOT_EXISTS);
  214 + }
  215 + }
  216 +
  217 +}
0 218 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/test/TestDemoServiceImpl.java deleted
1   -package cn.iocoder.yudao.module.infra.service.test;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoCreateReqVO;
5   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoExportReqVO;
6   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoPageReqVO;
7   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoUpdateReqVO;
8   -import cn.iocoder.yudao.module.infra.convert.test.TestDemoConvert;
9   -import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
10   -import cn.iocoder.yudao.module.infra.dal.mysql.test.TestDemoMapper;
11   -import org.springframework.cache.annotation.CacheEvict;
12   -import org.springframework.cache.annotation.Cacheable;
13   -import org.springframework.stereotype.Service;
14   -import org.springframework.validation.annotation.Validated;
15   -
16   -import javax.annotation.Resource;
17   -import java.util.Collection;
18   -import java.util.List;
19   -
20   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
21   -import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.TEST_DEMO_NOT_EXISTS;
22   -
23   -/**
24   - * 字典类型 Service 实现类
25   - *
26   - * @author 芋道源码
27   - */
28   -@Service
29   -@Validated
30   -public class TestDemoServiceImpl implements TestDemoService {
31   -
32   - @Resource
33   - private TestDemoMapper testDemoMapper;
34   -
35   - @Override
36   - public Long createTestDemo(TestDemoCreateReqVO createReqVO) {
37   - // 插入
38   - TestDemoDO testDemo = TestDemoConvert.INSTANCE.convert(createReqVO);
39   - testDemoMapper.insert(testDemo);
40   - // 返回
41   - return testDemo.getId();
42   - }
43   -
44   - @Override
45   - @CacheEvict(value = "test", key = "#updateReqVO.id")
46   - public void updateTestDemo(TestDemoUpdateReqVO updateReqVO) {
47   - // 校验存在
48   - validateTestDemoExists(updateReqVO.getId());
49   - // 更新
50   - TestDemoDO updateObj = TestDemoConvert.INSTANCE.convert(updateReqVO);
51   - testDemoMapper.updateById(updateObj);
52   - }
53   -
54   - @Override
55   - @CacheEvict(value = "test", key = "#id")
56   - public void deleteTestDemo(Long id) {
57   - // 校验存在
58   - validateTestDemoExists(id);
59   - // 删除
60   - testDemoMapper.deleteById(id);
61   - }
62   -
63   - private void validateTestDemoExists(Long id) {
64   - if (testDemoMapper.selectById(id) == null) {
65   - throw exception(TEST_DEMO_NOT_EXISTS);
66   - }
67   - }
68   -
69   - @Override
70   - @Cacheable(cacheNames = "test", key = "#id")
71   - public TestDemoDO getTestDemo(Long id) {
72   - return testDemoMapper.selectById(id);
73   - }
74   -
75   - @Override
76   - public List<TestDemoDO> getTestDemoList(Collection<Long> ids) {
77   - return testDemoMapper.selectBatchIds(ids);
78   - }
79   -
80   - @Override
81   - public PageResult<TestDemoDO> getTestDemoPage(TestDemoPageReqVO pageReqVO) {
82   -// testDemoMapper.selectList2();
83   - return testDemoMapper.selectPage(pageReqVO);
84   - }
85   -
86   - @Override
87   - public List<TestDemoDO> getTestDemoList(TestDemoExportReqVO exportReqVO) {
88   - return testDemoMapper.selectList(exportReqVO);
89   - }
90   -
91   -}
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/controller.vm
... ... @@ -15,8 +15,10 @@ import javax.servlet.http.*;
15 15 import java.util.*;
16 16 import java.io.IOException;
17 17  
  18 +import ${PageParamClassName};
18 19 import ${PageResultClassName};
19 20 import ${CommonResultClassName};
  21 +import ${BeanUtils};
20 22 import static ${CommonResultClassName}.success;
21 23  
22 24 import ${ExcelUtilsClassName};
... ... @@ -26,7 +28,10 @@ import static ${OperateTypeEnumClassName}.*;
26 28  
27 29 import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
28 30 import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
29   -import ${basePackage}.module.${table.moduleName}.convert.${table.businessName}.${table.className}Convert;
  31 +## 特殊:主子表专属逻辑
  32 +#foreach ($subTable in $subTables)
  33 +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
  34 +#end
30 35 import ${basePackage}.module.${table.moduleName}.service.${table.businessName}.${table.className}Service;
31 36  
32 37 @Tag(name = "${sceneEnum.name} - ${table.classComment}")
... ... @@ -41,17 +46,19 @@ public class ${sceneEnum.prefixClass}${table.className}Controller {
41 46  
42 47 @PostMapping("/create")
43 48 @Operation(summary = "创建${table.classComment}")
44   -#if ($sceneEnum.scene == 1) @PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')")#end
45   -
46   - public CommonResult<${primaryColumn.javaType}> create${simpleClassName}(@Valid @RequestBody ${sceneEnum.prefixClass}${table.className}CreateReqVO createReqVO) {
  49 +#if ($sceneEnum.scene == 1)
  50 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')")
  51 +#end
  52 + public CommonResult<${primaryColumn.javaType}> create${simpleClassName}(@Valid @RequestBody ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO) {
47 53 return success(${classNameVar}Service.create${simpleClassName}(createReqVO));
48 54 }
49 55  
50 56 @PutMapping("/update")
51 57 @Operation(summary = "更新${table.classComment}")
52   -#if ($sceneEnum.scene == 1) @PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')")#end
53   -
54   - public CommonResult<Boolean> update${simpleClassName}(@Valid @RequestBody ${sceneEnum.prefixClass}${table.className}UpdateReqVO updateReqVO) {
  58 +#if ($sceneEnum.scene == 1)
  59 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')")
  60 +#end
  61 + public CommonResult<Boolean> update${simpleClassName}(@Valid @RequestBody ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) {
55 62 ${classNameVar}Service.update${simpleClassName}(updateReqVO);
56 63 return success(true);
57 64 }
... ... @@ -59,8 +66,9 @@ public class ${sceneEnum.prefixClass}${table.className}Controller {
59 66 @DeleteMapping("/delete")
60 67 @Operation(summary = "删除${table.classComment}")
61 68 @Parameter(name = "id", description = "编号", required = true)
62   -#if ($sceneEnum.scene == 1) @PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')")#end
63   -
  69 +#if ($sceneEnum.scene == 1)
  70 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')")
  71 +#end
64 72 public CommonResult<Boolean> delete${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) {
65 73 ${classNameVar}Service.delete${simpleClassName}(id);
66 74 return success(true);
... ... @@ -69,43 +77,157 @@ public class ${sceneEnum.prefixClass}${table.className}Controller {
69 77 @GetMapping("/get")
70 78 @Operation(summary = "获得${table.classComment}")
71 79 @Parameter(name = "id", description = "编号", required = true, example = "1024")
72   -#if ($sceneEnum.scene == 1) @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")#end
73   -
  80 +#if ($sceneEnum.scene == 1)
  81 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
  82 +#end
74 83 public CommonResult<${sceneEnum.prefixClass}${table.className}RespVO> get${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) {
75 84 ${table.className}DO ${classNameVar} = ${classNameVar}Service.get${simpleClassName}(id);
76   - return success(${table.className}Convert.INSTANCE.convert(${classNameVar}));
77   - }
78   -
79   - @GetMapping("/list")
80   - @Operation(summary = "获得${table.classComment}列表")
81   - @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
82   -#if ($sceneEnum.scene == 1) @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")#end
83   -
84   - public CommonResult<List<${sceneEnum.prefixClass}${table.className}RespVO>> get${simpleClassName}List(@RequestParam("ids") Collection<${primaryColumn.javaType}> ids) {
85   - List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(ids);
86   - return success(${table.className}Convert.INSTANCE.convertList(list));
  85 + return success(BeanUtils.toBean(${classNameVar}, ${sceneEnum.prefixClass}${table.className}RespVO.class));
87 86 }
88 87  
  88 +#if ( $table.templateType != 2 )
89 89 @GetMapping("/page")
90 90 @Operation(summary = "获得${table.classComment}分页")
91   -#if ($sceneEnum.scene == 1) @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")#end
  91 +#if ($sceneEnum.scene == 1)
  92 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
  93 +#end
  94 + public CommonResult<PageResult<${sceneEnum.prefixClass}${table.className}RespVO>> get${simpleClassName}Page(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) {
  95 + PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(pageReqVO);
  96 + return success(BeanUtils.toBean(pageResult, ${sceneEnum.prefixClass}${table.className}RespVO.class));
  97 + }
92 98  
93   - public CommonResult<PageResult<${sceneEnum.prefixClass}${table.className}RespVO>> get${simpleClassName}Page(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageVO) {
94   - PageResult<${table.className}DO> pageResult = ${classNameVar}Service.get${simpleClassName}Page(pageVO);
95   - return success(${table.className}Convert.INSTANCE.convertPage(pageResult));
  99 +## 特殊:树表专属逻辑(树不需要分页接口)
  100 +#else
  101 + @GetMapping("/list")
  102 + @Operation(summary = "获得${table.classComment}列表")
  103 +#if ($sceneEnum.scene == 1)
  104 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
  105 +#end
  106 + public CommonResult<List<${sceneEnum.prefixClass}${table.className}RespVO>> get${simpleClassName}List(@Valid ${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) {
  107 + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(listReqVO);
  108 + return success(BeanUtils.toBean(list, ${sceneEnum.prefixClass}${table.className}RespVO.class));
96 109 }
97 110  
  111 +#end
98 112 @GetMapping("/export-excel")
99 113 @Operation(summary = "导出${table.classComment} Excel")
100   -#if ($sceneEnum.scene == 1) @PreAuthorize("@ss.hasPermission('${permissionPrefix}:export')")#end
101   -
  114 +#if ($sceneEnum.scene == 1)
  115 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:export')")
  116 +#end
102 117 @OperateLog(type = EXPORT)
103   - public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}ExportReqVO exportReqVO,
  118 +#if ( $table.templateType != 2 )
  119 + public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO,
  120 + HttpServletResponse response) throws IOException {
  121 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  122 + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}Page(pageReqVO).getList();
  123 + // 导出 Excel
  124 + ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${table.className}RespVO.class,
  125 + BeanUtils.toBean(list, ${table.className}RespVO.class));
  126 + }
  127 +## 特殊:树表专属逻辑(树不需要分页接口)
  128 +#else
  129 + public void export${simpleClassName}Excel(@Valid ${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO,
104 130 HttpServletResponse response) throws IOException {
105   - List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(exportReqVO);
  131 + List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(listReqVO);
106 132 // 导出 Excel
107   - List<${sceneEnum.prefixClass}${table.className}ExcelVO> datas = ${table.className}Convert.INSTANCE.convertList02(list);
108   - ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${sceneEnum.prefixClass}${table.className}ExcelVO.class, datas);
  133 + ExcelUtils.write(response, "${table.classComment}.xls", "数据", ${table.className}RespVO.class,
  134 + BeanUtils.toBean(list, ${table.className}RespVO.class));
  135 + }
  136 +#end
  137 +
  138 +## 特殊:主子表专属逻辑
  139 +#foreach ($subTable in $subTables)
  140 +#set ($index = $foreach.count - 1)
  141 +#set ($subSimpleClassName = $subSimpleClassNames.get($index))
  142 +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
  143 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  144 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  145 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  146 +#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  147 +#set ($subClassNameVar = $subClassNameVars.get($index))
  148 + // ==================== 子表($subTable.classComment) ====================
  149 +
  150 +## 情况一:MASTER_ERP 时,需要分查询页子表
  151 +#if ( $table.templateType == 11 )
  152 + @GetMapping("/${subSimpleClassName_strikeCase}/page")
  153 + @Operation(summary = "获得${subTable.classComment}分页")
  154 + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}")
  155 +#if ($sceneEnum.scene == 1)
  156 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
  157 +#end
  158 + public CommonResult<PageResult<${subTable.className}DO>> get${subSimpleClassName}Page(PageParam pageReqVO,
  159 + @RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  160 + return success(${classNameVar}Service.get${subSimpleClassName}Page(pageReqVO, ${subJoinColumn.javaField}));
  161 + }
  162 +
  163 +## 情况二:非 MASTER_ERP 时,需要列表查询子表
  164 +#else
  165 + #if ( $subTable.subJoinMany )
  166 + @GetMapping("/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}")
  167 + @Operation(summary = "获得${subTable.classComment}列表")
  168 + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}")
  169 +#if ($sceneEnum.scene == 1)
  170 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
  171 +#end
  172 + public CommonResult<List<${subTable.className}DO>> get${subSimpleClassName}ListBy${SubJoinColumnName}(@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  173 + return success(${classNameVar}Service.get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}));
  174 + }
  175 +
  176 + #else
  177 + @GetMapping("/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}")
  178 + @Operation(summary = "获得${subTable.classComment}")
  179 + @Parameter(name = "${subJoinColumn.javaField}", description = "${subJoinColumn.columnComment}")
  180 +#if ($sceneEnum.scene == 1)
  181 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
  182 +#end
  183 + public CommonResult<${subTable.className}DO> get${subSimpleClassName}By${SubJoinColumnName}(@RequestParam("${subJoinColumn.javaField}") ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  184 + return success(${classNameVar}Service.get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}));
  185 + }
  186 +
  187 + #end
  188 +#end
  189 +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作
  190 +#if ( $table.templateType == 11 )
  191 + @PostMapping("/${subSimpleClassName_strikeCase}/create")
  192 + @Operation(summary = "创建${subTable.classComment}")
  193 +#if ($sceneEnum.scene == 1)
  194 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:create')")
  195 +#end
  196 + public CommonResult<${subPrimaryColumn.javaType}> create${subSimpleClassName}(@Valid @RequestBody ${subTable.className}DO ${subClassNameVar}) {
  197 + return success(${classNameVar}Service.create${subSimpleClassName}(${subClassNameVar}));
  198 + }
  199 +
  200 + @PutMapping("/${subSimpleClassName_strikeCase}/update")
  201 + @Operation(summary = "更新${subTable.classComment}")
  202 +#if ($sceneEnum.scene == 1)
  203 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:update')")
  204 +#end
  205 + public CommonResult<Boolean> update${subSimpleClassName}(@Valid @RequestBody ${subTable.className}DO ${subClassNameVar}) {
  206 + ${classNameVar}Service.update${subSimpleClassName}(${subClassNameVar});
  207 + return success(true);
  208 + }
  209 +
  210 + @DeleteMapping("/${subSimpleClassName_strikeCase}/delete")
  211 + @Parameter(name = "id", description = "编号", required = true)
  212 + @Operation(summary = "删除${subTable.classComment}")
  213 +#if ($sceneEnum.scene == 1)
  214 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:delete')")
  215 +#end
  216 + public CommonResult<Boolean> delete${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) {
  217 + ${classNameVar}Service.delete${subSimpleClassName}(id);
  218 + return success(true);
109 219 }
110 220  
111   -}
  221 + @GetMapping("/${subSimpleClassName_strikeCase}/get")
  222 + @Operation(summary = "获得${subTable.classComment}")
  223 + @Parameter(name = "id", description = "编号", required = true)
  224 +#if ($sceneEnum.scene == 1)
  225 + @PreAuthorize("@ss.hasPermission('${permissionPrefix}:query')")
  226 +#end
  227 + public CommonResult<${subTable.className}DO> get${subSimpleClassName}(@RequestParam("id") ${subPrimaryColumn.javaType} id) {
  228 + return success(${classNameVar}Service.get${subSimpleClassName}(id));
  229 + }
  230 +
  231 +#end
  232 +#end
  233 +}
112 234 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/_column.vm deleted
1   -## 提供给 baseVO、createVO、updateVO 生成字段
2   - @Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end)
3   -#if (!${column.nullable})## 判断 @NotEmpty 和 @NotNull 注解
4   -#if (${field.fieldType} == 'String')
5   - @NotEmpty(message = "${column.columnComment}不能为空")
6   -#else
7   - @NotNull(message = "${column.columnComment}不能为空")
8   -#end
9   -#end
10   -#if (${column.javaType} == "LocalDateTime")## 时间类型
11   - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
12   -#end
13   - private ${column.javaType} ${column.javaField};
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/baseVO.vm deleted
1   -package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.*;
5   -import java.util.*;
6   -#foreach ($column in $columns)
7   -#if (${column.javaType} == "BigDecimal")
8   -import java.math.BigDecimal;
9   -#end
10   -#if (${column.javaType} == "LocalDateTime")
11   -import java.time.LocalDateTime;
12   -#end
13   -#end
14   -import javax.validation.constraints.*;
15   -## 处理 Date 字段的引入
16   -#foreach ($column in $columns)
17   -#if (${column.createOperation} && ${column.updateOperation} && ${column.listOperationResult}
18   - && ${column.javaType} == "LocalDateTime")## 时间类型
19   -import org.springframework.format.annotation.DateTimeFormat;
20   -
21   -import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
22   -#break
23   -#end
24   -#end
25   -
26   -/**
27   - * ${table.classComment} Base VO,提供给添加、修改、详细的子 VO 使用
28   - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
29   - */
30   -@Data
31   -public class ${sceneEnum.prefixClass}${table.className}BaseVO {
32   -
33   -#foreach ($column in $columns)
34   -#if (${column.createOperation} && ${column.updateOperation} && ${column.listOperationResult})##通用操作
35   - #parse("codegen/java/controller/vo/_column.vm")
36   -
37   -#end
38   -#end
39   -}
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/createReqVO.vm deleted
1   -package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
2   -
3   -import lombok.*;
4   -import java.util.*;
5   -import io.swagger.v3.oas.annotations.media.Schema;
6   -import javax.validation.constraints.*;
7   -## 处理 Date 字段的引入
8   -#foreach ($column in $columns)
9   -#if (${column.createOperation} && (!${column.updateOperation} || !${column.listOperationResult})
10   - && ${column.javaType} == "LocalDateTime")## 时间类型
11   -import org.springframework.format.annotation.DateTimeFormat;
12   -import java.time.LocalDateTime;
13   -import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
14   -#break
15   -#end
16   -#end
17   -
18   -@Schema(description = "${sceneEnum.name} - ${table.classComment}创建 Request VO")
19   -@Data
20   -@EqualsAndHashCode(callSuper = true)
21   -@ToString(callSuper = true)
22   -public class ${sceneEnum.prefixClass}${table.className}CreateReqVO extends ${sceneEnum.prefixClass}${table.className}BaseVO {
23   -
24   -#foreach ($column in $columns)
25   -#if (${column.createOperation} && (!${column.updateOperation} || !${column.listOperationResult}))##不是通用字段
26   - #parse("codegen/java/controller/vo/_column.vm")
27   -
28   -#end
29   -#end
30   -}
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/excelVO.vm deleted
1   -package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.*;
5   -import java.util.*;
6   -#foreach ($column in $columns)
7   -#if (${column.javaType} == "BigDecimal")
8   -import java.math.BigDecimal;
9   -#end
10   -#if (${column.javaType} == "LocalDateTime")
11   -import java.time.LocalDateTime;
12   -#end
13   -#end
14   -
15   -import com.alibaba.excel.annotation.ExcelProperty;
16   -#foreach ($column in $columns)
17   -#if ("$!column.dictType" != "")## 有设置数据字典
18   -import ${DictFormatClassName};
19   -import ${DictConvertClassName};
20   -
21   -#break
22   -#end
23   -#end
24   -
25   -/**
26   - * ${table.classComment} Excel VO
27   - *
28   - * @author ${table.author}
29   - */
30   -@Data
31   -public class ${sceneEnum.prefixClass}${table.className}ExcelVO {
32   -
33   -#foreach ($column in $columns)
34   - #if (${column.listOperationResult})##返回字段
35   - #if ("$!column.dictType" != "")##处理枚举值
36   - @ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class)
37   - @DictFormat("${column.dictType}") // TODO 代码优化:建议设置到对应的 XXXDictTypeConstants 枚举类中
38   - #else
39   - @ExcelProperty("${column.columnComment}")
40   - #end
41   - private ${column.javaType} ${column.javaField};
42   -
43   - #end
44   -#end
45   -}
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/exportReqVO.vm renamed to yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/listReqVO.vm
... ... @@ -4,9 +4,15 @@ import lombok.*;
4 4 import java.util.*;
5 5 import io.swagger.v3.oas.annotations.media.Schema;
6 6 import ${PageParamClassName};
7   -## 处理 Date 字段的引入
8 7 #foreach ($column in $columns)
9   -#if (${column.listOperation} && ${column.javaType} == "LocalDateTime")## 时间类型
  8 +#if (${column.javaType} == "BigDecimal")
  9 +import java.math.BigDecimal;
  10 +#break
  11 +#end
  12 +#end
  13 +## 处理 LocalDateTime 字段的引入
  14 +#foreach ($column in $columns)
  15 +#if (${column.listOperation} && ${column.javaType} == "LocalDateTime")
10 16 import java.time.LocalDateTime;
11 17 import org.springframework.format.annotation.DateTimeFormat;
12 18  
... ... @@ -20,9 +26,9 @@ import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
20 26 private ${column.javaType}#if ("$!prefix" != "") ${prefix}${JavaField}#else ${column.javaField}#end;
21 27 #end
22 28  
23   -@Schema(description = "${sceneEnum.name} - ${table.classComment} Excel 导出 Request VO,参数和 ${table.className}PageReqVO 是一致的")
  29 +@Schema(description = "${sceneEnum.name} - ${table.classComment}列表 Request VO")
24 30 @Data
25   -public class ${sceneEnum.prefixClass}${table.className}ExportReqVO {
  31 +public class ${sceneEnum.prefixClass}${table.className}ListReqVO {
26 32  
27 33 #foreach ($column in $columns)
28 34 #if (${column.listOperation})##查询操作
... ... @@ -36,4 +42,4 @@ public class ${sceneEnum.prefixClass}${table.className}ExportReqVO {
36 42  
37 43 #end
38 44 #end
39 45 -}
  46 +}
40 47 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/pageReqVO.vm
... ... @@ -4,9 +4,15 @@ import lombok.*;
4 4 import java.util.*;
5 5 import io.swagger.v3.oas.annotations.media.Schema;
6 6 import ${PageParamClassName};
7   -## 处理 Date 字段的引入
8 7 #foreach ($column in $columns)
9   -#if (${column.listOperation} && ${column.javaType} == "LocalDateTime")## 时间类型
  8 +#if (${column.javaType} == "BigDecimal")
  9 +import java.math.BigDecimal;
  10 +#break
  11 +#end
  12 +#end
  13 +## 处理 LocalDateTime 字段的引入
  14 +#foreach ($column in $columns)
  15 +#if (${column.listOperationCondition} && ${column.javaType} == "LocalDateTime")
10 16 import org.springframework.format.annotation.DateTimeFormat;
11 17 import java.time.LocalDateTime;
12 18  
... ... @@ -38,4 +44,4 @@ public class ${sceneEnum.prefixClass}${table.className}PageReqVO extends PagePar
38 44  
39 45 #end
40 46 #end
41 47 -}
  48 +}
42 49 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/respVO.vm
... ... @@ -2,24 +2,53 @@ package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePac
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.*;
  5 +import java.util.*;
  6 +## 处理 BigDecimal 字段的引入
  7 +import java.util.*;
5 8 #foreach ($column in $columns)
6   -#if (${column.javaType} == "LocalDateTime")
  9 +#if (${column.javaType} == "BigDecimal")
  10 +import java.math.BigDecimal;
  11 +#break
  12 +#end
  13 +#end
  14 +## 处理 LocalDateTime 字段的引入
  15 +#foreach ($column in $columns)
  16 +#if (${column.listOperationResult} && ${column.javaType} == "LocalDateTime")
  17 +import org.springframework.format.annotation.DateTimeFormat;
7 18 import java.time.LocalDateTime;
8 19 #break
9 20 #end
10 21 #end
  22 +## 处理 Excel 导出
  23 +import com.alibaba.excel.annotation.*;
  24 +#foreach ($column in $columns)
  25 +#if ("$!column.dictType" != "")## 有设置数据字典
  26 +import ${DictFormatClassName};
  27 +import ${DictConvertClassName};
  28 +#break
  29 +#end
  30 +#end
11 31  
12 32 @Schema(description = "${sceneEnum.name} - ${table.classComment} Response VO")
13 33 @Data
14   -@EqualsAndHashCode(callSuper = true)
15   -@ToString(callSuper = true)
16   -public class ${sceneEnum.prefixClass}${table.className}RespVO extends ${sceneEnum.prefixClass}${table.className}BaseVO {
  34 +@ExcelIgnoreUnannotated
  35 +public class ${sceneEnum.prefixClass}${table.className}RespVO {
17 36  
  37 +## 逐个处理字段
18 38 #foreach ($column in $columns)
19   -#if (${column.listOperationResult} && (!${column.createOperation} || !${column.updateOperation}))##不是通用字段
  39 +#if (${column.listOperationResult})
  40 +## 1. 处理 Swagger 注解
20 41 @Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end)
  42 +## 2. 处理 Excel 导出
  43 +#if ("$!column.dictType" != "")##处理枚举值
  44 + @ExcelProperty(value = "${column.columnComment}", converter = DictConvert.class)
  45 + @DictFormat("${column.dictType}") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  46 +#else
  47 + @ExcelProperty("${column.columnComment}")
  48 +#end
  49 +## 3. 处理字段定义
21 50 private ${column.javaType} ${column.javaField};
22 51  
23 52 #end
24 53 #end
25 54 -}
  55 +}
26 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/saveReqVO.vm 0 → 100644
  1 +package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import javax.validation.constraints.*;
  7 +## 处理 BigDecimal 字段的引入
  8 +import java.util.*;
  9 +#foreach ($column in $columns)
  10 +#if (${column.javaType} == "BigDecimal")
  11 +import java.math.BigDecimal;
  12 +#break
  13 +#end
  14 +#end
  15 +## 处理 LocalDateTime 字段的引入
  16 +#foreach ($column in $columns)
  17 +#if ((${column.createOperation} || ${column.updateOperation}) && ${column.javaType} == "LocalDateTime")
  18 +import org.springframework.format.annotation.DateTimeFormat;
  19 +import java.time.LocalDateTime;
  20 +#break
  21 +#end
  22 +#end
  23 +## 特殊:主子表专属逻辑
  24 +#foreach ($subTable in $subTables)
  25 +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
  26 +#end
  27 +
  28 +@Schema(description = "${sceneEnum.name} - ${table.classComment}新增/修改 Request VO")
  29 +@Data
  30 +public class ${sceneEnum.prefixClass}${table.className}SaveReqVO {
  31 +
  32 +## 逐个处理字段
  33 +#foreach ($column in $columns)
  34 +#if (${column.createOperation} || ${column.updateOperation})
  35 +## 1. 处理 Swagger 注解
  36 + @Schema(description = "${column.columnComment}"#if (!${column.nullable}), requiredMode = Schema.RequiredMode.REQUIRED#end#if ("$!column.example" != ""), example = "${column.example}"#end)
  37 +## 2. 处理 Validator 参数校验
  38 +#if (!${column.nullable} && !${column.primaryKey})
  39 +#if (${column.javaType} == 'String')
  40 + @NotEmpty(message = "${column.columnComment}不能为空")
  41 +#else
  42 + @NotNull(message = "${column.columnComment}不能为空")
  43 +#end
  44 +#end
  45 +## 3. 处理字段定义
  46 + private ${column.javaType} ${column.javaField};
  47 +
  48 +#end
  49 +#end
  50 +## 特殊:主子表专属逻辑(非 ERP 模式)
  51 +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
  52 +#foreach ($subTable in $subTables)
  53 +#set ($index = $foreach.count - 1)
  54 + #if ( $subTable.subJoinMany)
  55 + @Schema(description = "${subTable.classComment}列表")
  56 + private List<${subTable.className}DO> ${subClassNameVars.get($index)}s;
  57 +
  58 + #else
  59 + @Schema(description = "${subTable.classComment}")
  60 + private ${subTable.className}DO ${subClassNameVars.get($index)};
  61 +
  62 + #end
  63 +#end
  64 +#end
  65 +}
0 66 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/updateReqVO.vm deleted
1   -package ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.*;
5   -import java.util.*;
6   -import javax.validation.constraints.*;
7   -## 处理 Date 字段的引入
8   -#foreach ($column in $columns)
9   -#if (${column.updateOperation} && (!${column.createOperation} || !${column.listOperationResult})
10   - && ${column.javaType} == "LocalDateTime")## 时间类型
11   -import org.springframework.format.annotation.DateTimeFormat;
12   -import java.time.LocalDateTime;
13   -import static ${DateUtilsClassName}.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
14   -#break
15   -#end
16   -#end
17   -
18   -@Schema(description = "${sceneEnum.name} - ${table.classComment}更新 Request VO")
19   -@Data
20   -@EqualsAndHashCode(callSuper = true)
21   -@ToString(callSuper = true)
22   -public class ${sceneEnum.prefixClass}${table.className}UpdateReqVO extends ${sceneEnum.prefixClass}${table.className}BaseVO {
23   -
24   -#foreach ($column in $columns)
25   -#if (${column.updateOperation} && (!${column.createOperation} || !${column.listOperationResult}))##不是通用字段
26   - #parse("codegen/java/controller/vo/_column.vm")
27   -
28   -#end
29   -#end
30   -}
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/convert/convert.vm deleted
1   -package ${basePackage}.module.${table.moduleName}.convert.${table.businessName};
2   -
3   -import java.util.*;
4   -
5   -import ${PageResultClassName};
6   -
7   -import org.mapstruct.Mapper;
8   -import org.mapstruct.factory.Mappers;
9   -import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
10   -import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
11   -
12   -/**
13   - * ${table.classComment} Convert
14   - *
15   - * @author ${table.author}
16   - */
17   -@Mapper
18   -public interface ${table.className}Convert {
19   -
20   - ${table.className}Convert INSTANCE = Mappers.getMapper(${table.className}Convert.class);
21   -
22   - ${table.className}DO convert(${sceneEnum.prefixClass}${table.className}CreateReqVO bean);
23   -
24   - ${table.className}DO convert(${sceneEnum.prefixClass}${table.className}UpdateReqVO bean);
25   -
26   - ${sceneEnum.prefixClass}${table.className}RespVO convert(${table.className}DO bean);
27   -
28   - List<${sceneEnum.prefixClass}${table.className}RespVO> convertList(List<${table.className}DO> list);
29   -
30   - PageResult<${sceneEnum.prefixClass}${table.className}RespVO> convertPage(PageResult<${table.className}DO> page);
31   -
32   - List<${sceneEnum.prefixClass}${table.className}ExcelVO> convertList02(List<${table.className}DO> list);
33   -
34   -}
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do.vm
... ... @@ -28,6 +28,11 @@ import ${BaseDOClassName};
28 28 @AllArgsConstructor
29 29 public class ${table.className}DO extends BaseDO {
30 30  
  31 +## 特殊:树表专属逻辑
  32 +#if ( $table.templateType == 2 )
  33 + public static final Long ${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT = 0L;
  34 +
  35 +#end
31 36 #foreach ($column in $columns)
32 37 #if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段
33 38 /**
... ... @@ -44,4 +49,4 @@ public class ${table.className}DO extends BaseDO {
44 49 #end
45 50 #end
46 51  
47 52 -}
  53 +}
48 54 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/do_sub.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +package ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName};
  4 +
  5 +import lombok.*;
  6 +import java.util.*;
  7 +#foreach ($column in $subColumns)
  8 +#if (${column.javaType} == "BigDecimal")
  9 +import java.math.BigDecimal;
  10 +#end
  11 +#if (${column.javaType} == "LocalDateTime")
  12 +import java.time.LocalDateTime;
  13 +#end
  14 +#end
  15 +import com.baomidou.mybatisplus.annotation.*;
  16 +import ${BaseDOClassName};
  17 +
  18 +/**
  19 + * ${subTable.classComment} DO
  20 + *
  21 + * @author ${subTable.author}
  22 + */
  23 +@TableName("${subTable.tableName.toLowerCase()}")
  24 +@KeySequence("${subTable.tableName.toLowerCase()}_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  25 +@Data
  26 +@EqualsAndHashCode(callSuper = true)
  27 +@ToString(callSuper = true)
  28 +@Builder
  29 +@NoArgsConstructor
  30 +@AllArgsConstructor
  31 +public class ${subTable.className}DO extends BaseDO {
  32 +
  33 +#foreach ($column in $subColumns)
  34 +#if (!${baseDOFields.contains(${column.javaField})})##排除 BaseDO 的字段
  35 + /**
  36 + * ${column.columnComment}
  37 + #if ("$!column.dictType" != "")##处理枚举值
  38 + *
  39 + * 枚举 {@link TODO ${column.dictType} 对应的类}
  40 + #end
  41 + */
  42 + #if (${column.primaryKey})##处理主键
  43 + @TableId#if (${column.javaType} == 'String')(type = IdType.INPUT)#end
  44 + #end
  45 + private ${column.javaType} ${column.javaField};
  46 +#end
  47 +#end
  48 +
  49 +}
0 50 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.vm
... ... @@ -49,18 +49,34 @@ import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePack
49 49 @Mapper
50 50 public interface ${table.className}Mapper extends BaseMapperX<${table.className}DO> {
51 51  
  52 +## 特殊:树表专属逻辑(树不需要分页接口)
  53 +#if ( $table.templateType != 2 )
52 54 default PageResult<${table.className}DO> selectPage(${sceneEnum.prefixClass}${table.className}PageReqVO reqVO) {
53 55 return selectPage(reqVO, new LambdaQueryWrapperX<${table.className}DO>()
54 56 #listCondition()
55 57 .orderByDesc(${table.className}DO::getId));## 大多数情况下,id 倒序
56 58  
57 59 }
58   -
59   - default List<${table.className}DO> selectList(${sceneEnum.prefixClass}${table.className}ExportReqVO reqVO) {
  60 +#else
  61 + default List<${table.className}DO> selectList(${sceneEnum.prefixClass}${table.className}ListReqVO reqVO) {
60 62 return selectList(new LambdaQueryWrapperX<${table.className}DO>()
61 63 #listCondition()
62 64 .orderByDesc(${table.className}DO::getId));## 大多数情况下,id 倒序
63 65  
64 66 }
  67 +#end
  68 +
  69 +## 特殊:树表专属逻辑
  70 +#if ( $table.templateType == 2 )
  71 +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  72 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
  73 + default ${table.className}DO selectBy${TreeParentJavaField}And${TreeNameJavaField}(Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) {
  74 + return selectOne(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField}, ${table.className}DO::get${TreeNameJavaField}, ${treeNameColumn.javaField});
  75 + }
  76 +
  77 + default Long selectCountBy${TreeParentJavaField}(${treeParentColumn.javaType} ${treeParentColumn.javaField}) {
  78 + return selectCount(${table.className}DO::get${TreeParentJavaField}, ${treeParentColumn.javaField});
  79 + }
65 80  
66   -}
  81 +#end
  82 +}
67 83 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper.xml.vm
... ... @@ -9,4 +9,4 @@
9 9 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
10 10 -->
11 11  
12 12 -</mapper>
  13 +</mapper>
13 14 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/dal/mapper_sub.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subJoinColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  5 +package ${basePackage}.module.${subTable.moduleName}.dal.mysql.${subTable.businessName};
  6 +
  7 +import java.util.*;
  8 +
  9 +import ${PageResultClassName};
  10 +import ${PageParamClassName};
  11 +import ${QueryWrapperClassName};
  12 +import ${BaseMapperClassName};
  13 +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
  14 +import org.apache.ibatis.annotations.Mapper;
  15 +
  16 +/**
  17 + * ${subTable.classComment} Mapper
  18 + *
  19 + * @author ${subTable.author}
  20 + */
  21 +@Mapper
  22 +public interface ${subTable.className}Mapper extends BaseMapperX<${subTable.className}DO> {
  23 +
  24 +## 情况一:MASTER_ERP 时,需要分查询页子表
  25 +#if ( $table.templateType == 11 )
  26 + default PageResult<${subTable.className}DO> selectPage(PageParam reqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  27 + return selectPage(reqVO, new LambdaQueryWrapperX<${subTable.className}DO>()
  28 + .eq(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField})
  29 + .orderByDesc(${subTable.className}DO::getId));## 大多数情况下,id 倒序
  30 +
  31 + }
  32 +
  33 +## 情况二:非 MASTER_ERP 时,需要列表查询子表
  34 +#else
  35 + #if ( $subTable.subJoinMany)
  36 + default List<${subTable.className}DO> selectListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  37 + return selectList(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField});
  38 + }
  39 +
  40 + #else
  41 + default ${subTable.className}DO selectBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  42 + return selectOne(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField});
  43 + }
  44 +
  45 + #end
  46 + #end
  47 + default int deleteBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  48 + return delete(${subTable.className}DO::get${SubJoinColumnName}, ${subJoinColumn.javaField});
  49 + }
  50 +
  51 +}
0 52 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/enums/errorcode.vm
1 1 // TODO 待办:请将下面的错误码复制到 yudao-module-${table.moduleName}-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
2 2 // ========== ${table.classComment} TODO 补充编号 ==========
3 3 ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS = new ErrorCode(TODO 补充编号, "${table.classComment}不存在");
  4 +## 特殊:树表专属逻辑
  5 +#if ( $table.templateType == 2 )
  6 +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN = new ErrorCode(TODO 补充编号, "存在存在子${table.classComment},无法删除");
  7 +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS = new ErrorCode(TODO 补充编号,"父级${table.classComment}不存在");
  8 +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR = new ErrorCode(TODO 补充编号, "不能设置自己为父${table.classComment}");
  9 +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE = new ErrorCode(TODO 补充编号, "已经存在该${treeNameColumn.columnComment}的${table.classComment}");
  10 +ErrorCode ${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD = new ErrorCode(TODO 补充编号, "不能设置自己的子${table.className}为父${table.className}");
  11 +#end
  12 +## 特殊:主子表专属逻辑
  13 +#if ( $table.templateType == 11 )## 特殊:ERP 情况
  14 +#foreach ($subTable in $subTables)
  15 +#set ($index = $foreach.count - 1)
  16 +#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index))
  17 +ErrorCode ${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS = new ErrorCode(TODO 补充编号, "${subTable.classComment}不存在");
  18 +#if ( !$subTable.subJoinMany )
  19 +ErrorCode ${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS = new ErrorCode(TODO 补充编号, "${subTable.classComment}已存在");
  20 +#end
  21 +#end
  22 +#end
4 23 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/service.vm
... ... @@ -4,7 +4,12 @@ import java.util.*;
4 4 import javax.validation.*;
5 5 import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
6 6 import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
  7 +## 特殊:主子表专属逻辑
  8 +#foreach ($subTable in $subTables)
  9 +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
  10 +#end
7 11 import ${PageResultClassName};
  12 +import ${PageParamClassName};
8 13  
9 14 /**
10 15 * ${table.classComment} Service 接口
... ... @@ -19,14 +24,14 @@ public interface ${table.className}Service {
19 24 * @param createReqVO 创建信息
20 25 * @return 编号
21 26 */
22   - ${primaryColumn.javaType} create${simpleClassName}(@Valid ${sceneEnum.prefixClass}${table.className}CreateReqVO createReqVO);
  27 + ${primaryColumn.javaType} create${simpleClassName}(@Valid ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO);
23 28  
24 29 /**
25 30 * 更新${table.classComment}
26 31 *
27 32 * @param updateReqVO 更新信息
28 33 */
29   - void update${simpleClassName}(@Valid ${sceneEnum.prefixClass}${table.className}UpdateReqVO updateReqVO);
  34 + void update${simpleClassName}(@Valid ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO);
30 35  
31 36 /**
32 37 * 删除${table.classComment}
... ... @@ -43,28 +48,100 @@ public interface ${table.className}Service {
43 48 */
44 49 ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id);
45 50  
  51 +## 特殊:树表专属逻辑(树不需要分页接口)
  52 +#if ( $table.templateType != 2 )
  53 + /**
  54 + * 获得${table.classComment}分页
  55 + *
  56 + * @param pageReqVO 分页查询
  57 + * @return ${table.classComment}分页
  58 + */
  59 + PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO);
  60 +#else
46 61 /**
47 62 * 获得${table.classComment}列表
48 63 *
49   - * @param ids 编号
  64 + * @param listReqVO 查询条件
50 65 * @return ${table.classComment}列表
51 66 */
52   - List<${table.className}DO> get${simpleClassName}List(Collection<${primaryColumn.javaType}> ids);
  67 + List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO);
  68 +#end
  69 +
  70 +## 特殊:主子表专属逻辑
  71 +#foreach ($subTable in $subTables)
  72 +#set ($index = $foreach.count - 1)
  73 +#set ($subSimpleClassName = $subSimpleClassNames.get($index))
  74 +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
  75 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  76 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  77 +#set ($subClassNameVar = $subClassNameVars.get($index))
  78 + // ==================== 子表($subTable.classComment) ====================
53 79  
  80 +## 情况一:MASTER_ERP 时,需要分查询页子表
  81 +#if ( $table.templateType == 11 )
54 82 /**
55   - * 获得${table.classComment}分页
  83 + * 获得${subTable.classComment}分页
56 84 *
57 85 * @param pageReqVO 分页查询
58   - * @return ${table.classComment}分页
  86 + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment}
  87 + * @return ${subTable.classComment}分页
59 88 */
60   - PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO);
  89 + PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField});
61 90  
  91 +## 情况二:非 MASTER_ERP 时,需要列表查询子表
  92 +#else
  93 + #if ( $subTable.subJoinMany )
62 94 /**
63   - * 获得${table.classComment}列表, 用于 Excel 导出
  95 + * 获得${subTable.classComment}列表
64 96 *
65   - * @param exportReqVO 查询条件
66   - * @return ${table.classComment}列表
  97 + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment}
  98 + * @return ${subTable.classComment}列表
  99 + */
  100 + List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField});
  101 +
  102 + #else
  103 + /**
  104 + * 获得${subTable.classComment}
  105 + *
  106 + * @param ${subJoinColumn.javaField} ${subJoinColumn.columnComment}
  107 + * @return ${subTable.classComment}
67 108 */
68   - List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ExportReqVO exportReqVO);
  109 + ${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField});
  110 +
  111 + #end
  112 +#end
  113 +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作
  114 +#if ( $table.templateType == 11 )
  115 + /**
  116 + * 创建${subTable.classComment}
  117 + *
  118 + * @param ${subClassNameVar} 创建信息
  119 + * @return 编号
  120 + */
  121 + ${subPrimaryColumn.javaType} create${subSimpleClassName}(@Valid ${subTable.className}DO ${subClassNameVar});
  122 +
  123 + /**
  124 + * 更新${subTable.classComment}
  125 + *
  126 + * @param ${subClassNameVar} 更新信息
  127 + */
  128 + void update${subSimpleClassName}(@Valid ${subTable.className}DO ${subClassNameVar});
  129 +
  130 + /**
  131 + * 删除${subTable.classComment}
  132 + *
  133 + * @param id 编号
  134 + */
  135 + void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id);
  136 +
  137 + /**
  138 + * 获得${subTable.classComment}
  139 + *
  140 + * @param id 编号
  141 + * @return ${subTable.classComment}
  142 + */
  143 + ${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id);
69 144  
70   -}
  145 +#end
  146 +#end
  147 +}
71 148 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm
... ... @@ -3,21 +3,29 @@ package ${basePackage}.module.${table.moduleName}.service.${table.businessName};
3 3 import org.springframework.stereotype.Service;
4 4 import javax.annotation.Resource;
5 5 import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.transaction.annotation.Transactional;
6 7  
7 8 import java.util.*;
8 9 import ${basePackage}.module.${table.moduleName}.controller.${sceneEnum.basePackage}.${table.businessName}.vo.*;
9 10 import ${basePackage}.module.${table.moduleName}.dal.dataobject.${table.businessName}.${table.className}DO;
  11 +## 特殊:主子表专属逻辑
  12 +#foreach ($subTable in $subTables)
  13 +import ${basePackage}.module.${subTable.moduleName}.dal.dataobject.${subTable.businessName}.${subTable.className}DO;
  14 +#end
10 15 import ${PageResultClassName};
  16 +import ${PageParamClassName};
  17 +import ${BeanUtils};
11 18  
12   -import ${basePackage}.module.${table.moduleName}.convert.${table.businessName}.${table.className}Convert;
13 19 import ${basePackage}.module.${table.moduleName}.dal.mysql.${table.businessName}.${table.className}Mapper;
  20 +## 特殊:主子表专属逻辑
  21 +#foreach ($subTable in $subTables)
  22 +#set ($index = $foreach.count - 1)
  23 +import ${basePackage}.module.${subTable.moduleName}.dal.mysql.${subTable.businessName}.${subTable.className}Mapper;
  24 +#end
14 25  
15 26 import static ${ServiceExceptionUtilClassName}.exception;
16 27 import static ${basePackage}.module.${table.moduleName}.enums.ErrorCodeConstants.*;
17 28  
18   -import cn.hutool.core.collection.CollUtil;
19   -import cn.hutool.core.collection.ListUtil;
20   -
21 29 /**
22 30 * ${table.classComment} Service 实现类
23 31 *
... ... @@ -29,31 +37,121 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
29 37  
30 38 @Resource
31 39 private ${table.className}Mapper ${classNameVar}Mapper;
  40 +## 特殊:主子表专属逻辑
  41 +#foreach ($subTable in $subTables)
  42 +#set ($index = $foreach.count - 1)
  43 + @Resource
  44 + private ${subTable.className}Mapper ${subClassNameVars.get($index)}Mapper;
  45 +#end
32 46  
33 47 @Override
34   - public ${primaryColumn.javaType} create${simpleClassName}(${sceneEnum.prefixClass}${table.className}CreateReqVO createReqVO) {
  48 +## 特殊:主子表专属逻辑(非 ERP 模式)
  49 +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
  50 + @Transactional(rollbackFor = Exception.class)
  51 +#end
  52 + public ${primaryColumn.javaType} create${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO) {
  53 +## 特殊:树表专属逻辑
  54 +#if ( $table.templateType == 2 )
  55 +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  56 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
  57 + // 校验${treeParentColumn.columnComment}的有效性
  58 + validateParent${simpleClassName}(null, createReqVO.get${TreeParentJavaField}());
  59 + // 校验${treeNameColumn.columnComment}的唯一性
  60 + validate${simpleClassName}${TreeNameJavaField}Unique(null, createReqVO.get${TreeParentJavaField}(), createReqVO.get${TreeNameJavaField}());
  61 +
  62 +#end
35 63 // 插入
36   - ${table.className}DO ${classNameVar} = ${table.className}Convert.INSTANCE.convert(createReqVO);
  64 + ${table.className}DO ${classNameVar} = BeanUtils.toBean(createReqVO, ${table.className}DO.class);
37 65 ${classNameVar}Mapper.insert(${classNameVar});
  66 +## 特殊:主子表专属逻辑(非 ERP 模式)
  67 +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
  68 +
  69 + // 插入子表
  70 +#foreach ($subTable in $subTables)
  71 +#set ($index = $foreach.count - 1)
  72 +#set ($subSimpleClassName = $subSimpleClassNames.get($index))
  73 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  74 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  75 + #if ( $subTable.subJoinMany)
  76 + create${subSimpleClassName}List(${classNameVar}.getId(), createReqVO.get${subSimpleClassNames.get($index)}s());
  77 + #else
  78 + create${subSimpleClassName}(${classNameVar}.getId(), createReqVO.get${subSimpleClassNames.get($index)}());
  79 + #end
  80 +#end
  81 +#end
38 82 // 返回
39 83 return ${classNameVar}.getId();
40 84 }
41 85  
42 86 @Override
43   - public void update${simpleClassName}(${sceneEnum.prefixClass}${table.className}UpdateReqVO updateReqVO) {
  87 +## 特殊:主子表专属逻辑(非 ERP 模式)
  88 +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11 )
  89 + @Transactional(rollbackFor = Exception.class)
  90 +#end
  91 + public void update${simpleClassName}(${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO) {
44 92 // 校验存在
45 93 validate${simpleClassName}Exists(updateReqVO.getId());
  94 +## 特殊:树表专属逻辑
  95 +#if ( $table.templateType == 2 )
  96 +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  97 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
  98 + // 校验${treeParentColumn.columnComment}的有效性
  99 + validateParent${simpleClassName}(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}());
  100 + // 校验${treeNameColumn.columnComment}的唯一性
  101 + validate${simpleClassName}${TreeNameJavaField}Unique(updateReqVO.getId(), updateReqVO.get${TreeParentJavaField}(), updateReqVO.get${TreeNameJavaField}());
  102 +
  103 +#end
46 104 // 更新
47   - ${table.className}DO updateObj = ${table.className}Convert.INSTANCE.convert(updateReqVO);
  105 + ${table.className}DO updateObj = BeanUtils.toBean(updateReqVO, ${table.className}DO.class);
48 106 ${classNameVar}Mapper.updateById(updateObj);
  107 +## 特殊:主子表专属逻辑(非 ERP 模式)
  108 +#if ( $subTables && $subTables.size() > 0 && $table.templateType != 11)
  109 +
  110 + // 更新子表
  111 +#foreach ($subTable in $subTables)
  112 +#set ($index = $foreach.count - 1)
  113 +#set ($subSimpleClassName = $subSimpleClassNames.get($index))
  114 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  115 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  116 + #if ( $subTable.subJoinMany)
  117 + update${subSimpleClassName}List(updateReqVO.getId(), updateReqVO.get${subSimpleClassNames.get($index)}s());
  118 + #else
  119 + update${subSimpleClassName}(updateReqVO.getId(), updateReqVO.get${subSimpleClassNames.get($index)}());
  120 + #end
  121 +#end
  122 +#end
49 123 }
50 124  
51 125 @Override
  126 +## 特殊:主子表专属逻辑
  127 +#if ( $subTables && $subTables.size() > 0)
  128 + @Transactional(rollbackFor = Exception.class)
  129 +#end
52 130 public void delete${simpleClassName}(${primaryColumn.javaType} id) {
53 131 // 校验存在
54 132 validate${simpleClassName}Exists(id);
  133 +## 特殊:树表专属逻辑
  134 +#if ( $table.templateType == 2 )
  135 +#set ($ParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  136 + // 校验是否有子${table.classComment}
  137 + if (${classNameVar}Mapper.selectCountBy${ParentJavaField}(id) > 0) {
  138 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_EXITS_CHILDREN);
  139 + }
  140 +#end
55 141 // 删除
56 142 ${classNameVar}Mapper.deleteById(id);
  143 +## 特殊:主子表专属逻辑
  144 +#if ( $subTables && $subTables.size() > 0)
  145 +
  146 + // 删除子表
  147 +#foreach ($subTable in $subTables)
  148 +#set ($index = $foreach.count - 1)
  149 +#set ($subSimpleClassName = $subSimpleClassNames.get($index))
  150 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  151 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  152 + delete${subSimpleClassName}By${SubJoinColumnName}(id);
  153 +#end
  154 +#end
57 155 }
58 156  
59 157 private void validate${simpleClassName}Exists(${primaryColumn.javaType} id) {
... ... @@ -62,27 +160,191 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
62 160 }
63 161 }
64 162  
  163 +## 特殊:树表专属逻辑
  164 +#if ( $table.templateType == 2 )
  165 +#set ($TreeParentJavaField = $treeParentColumn.javaField.substring(0,1).toUpperCase() + ${treeParentColumn.javaField.substring(1)})##首字母大写
  166 +#set ($TreeNameJavaField = $treeNameColumn.javaField.substring(0,1).toUpperCase() + ${treeNameColumn.javaField.substring(1)})##首字母大写
  167 + private void validateParent${simpleClassName}(Long id, Long ${treeParentColumn.javaField}) {
  168 + if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) {
  169 + return;
  170 + }
  171 + // 1. 不能设置自己为父${table.classComment}
  172 + if (Objects.equals(id, ${treeParentColumn.javaField})) {
  173 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_ERROR);
  174 + }
  175 + // 2. 父${table.classComment}不存在
  176 + ${simpleClassName}DO parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField});
  177 + if (parent${simpleClassName} == null) {
  178 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_NOT_EXITS);
  179 + }
  180 + // 3. 递归校验父${table.classComment},如果父${table.classComment}是自己的子${table.classComment},则报错,避免形成环路
  181 + if (id == null) { // id 为空,说明新增,不需要考虑环路
  182 + return;
  183 + }
  184 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  185 + // 3.1 校验环路
  186 + ${treeParentColumn.javaField} = parent${simpleClassName}.get${TreeParentJavaField}();
  187 + if (Objects.equals(id, ${treeParentColumn.javaField})) {
  188 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_PARENT_IS_CHILD);
  189 + }
  190 + // 3.2 继续递归下一级父${table.classComment}
  191 + if (${treeParentColumn.javaField} == null || ${simpleClassName}DO.${treeParentColumn_javaField_underlineCase.toUpperCase()}_ROOT.equals(${treeParentColumn.javaField})) {
  192 + break;
  193 + }
  194 + parent${simpleClassName} = ${classNameVar}Mapper.selectById(${treeParentColumn.javaField});
  195 + if (parent${simpleClassName} == null) {
  196 + break;
  197 + }
  198 + }
  199 + }
  200 +
  201 + private void validate${simpleClassName}${TreeNameJavaField}Unique(Long id, Long ${treeParentColumn.javaField}, String ${treeNameColumn.javaField}) {
  202 + ${simpleClassName}DO ${classNameVar} = ${classNameVar}Mapper.selectBy${TreeParentJavaField}And${TreeNameJavaField}(${treeParentColumn.javaField}, ${treeNameColumn.javaField});
  203 + if (${classNameVar} == null) {
  204 + return;
  205 + }
  206 + // 如果 id 为空,说明不用比较是否为相同 id 的${table.classComment}
  207 + if (id == null) {
  208 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE);
  209 + }
  210 + if (!Objects.equals(${classNameVar}.getId(), id)) {
  211 + throw exception(${simpleClassName_underlineCase.toUpperCase()}_${treeNameColumn_javaField_underlineCase.toUpperCase()}_DUPLICATE);
  212 + }
  213 + }
  214 +
  215 +#end
65 216 @Override
66 217 public ${table.className}DO get${simpleClassName}(${primaryColumn.javaType} id) {
67 218 return ${classNameVar}Mapper.selectById(id);
68 219 }
69 220  
  221 +## 特殊:树表专属逻辑(树不需要分页接口)
  222 +#if ( $table.templateType != 2 )
  223 + @Override
  224 + public PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) {
  225 + return ${classNameVar}Mapper.selectPage(pageReqVO);
  226 + }
  227 +#else
  228 + @Override
  229 + public List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ListReqVO listReqVO) {
  230 + return ${classNameVar}Mapper.selectList(listReqVO);
  231 + }
  232 +#end
  233 +
  234 +## 特殊:主子表专属逻辑
  235 +#foreach ($subTable in $subTables)
  236 +#set ($index = $foreach.count - 1)
  237 +#set ($subSimpleClassName = $subSimpleClassNames.get($index))
  238 +#set ($simpleClassNameUnderlineCase = $simpleClassNameUnderlineCases.get($index))
  239 +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
  240 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  241 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  242 +#set ($subClassNameVar = $subClassNameVars.get($index))
  243 + // ==================== 子表($subTable.classComment) ====================
  244 +
  245 +## 情况一:MASTER_ERP 时,需要分查询页子表
  246 +#if ( $table.templateType == 11 )
  247 + @Override
  248 + public PageResult<${subTable.className}DO> get${subSimpleClassName}Page(PageParam pageReqVO, ${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  249 + return ${subClassNameVars.get($index)}Mapper.selectPage(pageReqVO, ${subJoinColumn.javaField});
  250 + }
  251 +
  252 +## 情况二:非 MASTER_ERP 时,需要列表查询子表
  253 +#else
  254 + #if ( $subTable.subJoinMany )
70 255 @Override
71   - public List<${table.className}DO> get${simpleClassName}List(Collection<${primaryColumn.javaType}> ids) {
72   - if (CollUtil.isEmpty(ids)) {
73   - return ListUtil.empty();
  256 + public List<${subTable.className}DO> get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  257 + return ${subClassNameVars.get($index)}Mapper.selectListBy${SubJoinColumnName}(${subJoinColumn.javaField});
  258 + }
  259 +
  260 + #else
  261 + @Override
  262 + public ${subTable.className}DO get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaType} ${subJoinColumn.javaField}) {
  263 + return ${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subJoinColumn.javaField});
  264 + }
  265 +
  266 + #end
  267 +#end
  268 +## 情况一:MASTER_ERP 时,支持单个的新增、修改、删除操作
  269 +#if ( $table.templateType == 11 )
  270 + @Override
  271 + public ${subPrimaryColumn.javaType} create${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) {
  272 +## 特殊:一对一时,需要保证只有一条,不能重复插入
  273 +#if ( !$subTable.subJoinMany)
  274 + // 校验是否已经存在
  275 + if (${subClassNameVars.get($index)}Mapper.selectBy${SubJoinColumnName}(${subClassNameVar}.get${SubJoinColumnName}()) != null) {
  276 + throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_EXISTS);
74 277 }
75   - return ${classNameVar}Mapper.selectBatchIds(ids);
  278 + // 插入
  279 +#end
  280 + ${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar});
  281 + return ${subClassNameVar}.getId();
76 282 }
77 283  
78 284 @Override
79   - public PageResult<${table.className}DO> get${simpleClassName}Page(${sceneEnum.prefixClass}${table.className}PageReqVO pageReqVO) {
80   - return ${classNameVar}Mapper.selectPage(pageReqVO);
  285 + public void update${subSimpleClassName}(${subTable.className}DO ${subClassNameVar}) {
  286 + // 校验存在
  287 + validate${subSimpleClassName}Exists(${subClassNameVar}.getId());
  288 + // 更新
  289 + ${subClassNameVars.get($index)}Mapper.updateById(${subClassNameVar});
  290 + }
  291 +
  292 + @Override
  293 + public void delete${subSimpleClassName}(${subPrimaryColumn.javaType} id) {
  294 + // 校验存在
  295 + validate${subSimpleClassName}Exists(id);
  296 + // 删除
  297 + ${subClassNameVars.get($index)}Mapper.deleteById(id);
81 298 }
82 299  
83 300 @Override
84   - public List<${table.className}DO> get${simpleClassName}List(${sceneEnum.prefixClass}${table.className}ExportReqVO exportReqVO) {
85   - return ${classNameVar}Mapper.selectList(exportReqVO);
  301 + public ${subTable.className}DO get${subSimpleClassName}(${subPrimaryColumn.javaType} id) {
  302 + return ${subClassNameVars.get($index)}Mapper.selectById(id);
  303 + }
  304 +
  305 + private void validate${subSimpleClassName}Exists(${subPrimaryColumn.javaType} id) {
  306 + if (${subClassNameVar}Mapper.selectById(id) == null) {
  307 + throw exception(${simpleClassNameUnderlineCase.toUpperCase()}_NOT_EXISTS);
  308 + }
  309 + }
  310 +
  311 +## 情况二:非 MASTER_ERP 时,支持批量的新增、修改操作
  312 +#else
  313 + #if ( $subTable.subJoinMany)
  314 + private void create${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) {
  315 + list.forEach(o -> o.set$SubJoinColumnName(${subJoinColumn.javaField}));
  316 + ${subClassNameVars.get($index)}Mapper.insertBatch(list);
  317 + }
  318 +
  319 + private void update${subSimpleClassName}List(${primaryColumn.javaType} ${subJoinColumn.javaField}, List<${subTable.className}DO> list) {
  320 + delete${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField});
  321 + list.forEach(o -> o.setId(null).setUpdater(null).setUpdateTime(null)); // 解决更新情况下:1)id 冲突;2)updateTime 不更新
  322 + create${subSimpleClassName}List(${subJoinColumn.javaField}, list);
  323 + }
  324 +
  325 + #else
  326 + private void create${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) {
  327 + if (${subClassNameVar} == null) {
  328 + return;
  329 + }
  330 + ${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField});
  331 + ${subClassNameVars.get($index)}Mapper.insert(${subClassNameVar});
  332 + }
  333 +
  334 + private void update${subSimpleClassName}(${primaryColumn.javaType} ${subJoinColumn.javaField}, ${subTable.className}DO ${subClassNameVar}) {
  335 + if (${subClassNameVar} == null) {
  336 + return;
  337 + }
  338 + ${subClassNameVar}.set$SubJoinColumnName(${subJoinColumn.javaField});
  339 + ${subClassNameVar}.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新
  340 + ${subClassNameVars.get($index)}Mapper.insertOrUpdate(${subClassNameVar});
  341 + }
  342 +
  343 + #end
  344 +#end
  345 + private void delete${subSimpleClassName}By${SubJoinColumnName}(${primaryColumn.javaType} ${subJoinColumn.javaField}) {
  346 + ${subClassNameVars.get($index)}Mapper.deleteBy${SubJoinColumnName}(${subJoinColumn.javaField});
86 347 }
87 348  
88   -}
  349 +#end
  350 +}
89 351 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/test/serviceTest.vm
... ... @@ -77,15 +77,15 @@ public class ${table.className}ServiceImplTest extends BaseDbUnitTest {
77 77 @Test
78 78 public void testCreate${simpleClassName}_success() {
79 79 // 准备参数
80   - ${sceneEnum.prefixClass}${table.className}CreateReqVO reqVO = randomPojo(${sceneEnum.prefixClass}${table.className}CreateReqVO.class);
  80 + ${sceneEnum.prefixClass}${table.className}SaveReqVO createReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class).setId(null);
81 81  
82 82 // 调用
83   - ${primaryColumn.javaType} ${classNameVar}Id = ${classNameVar}Service.create${simpleClassName}(reqVO);
  83 + ${primaryColumn.javaType} ${classNameVar}Id = ${classNameVar}Service.create${simpleClassName}(createReqVO);
84 84 // 断言
85 85 assertNotNull(${classNameVar}Id);
86 86 // 校验记录的属性是否正确
87 87 ${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(${classNameVar}Id);
88   - assertPojoEquals(reqVO, ${classNameVar});
  88 + assertPojoEquals(createReqVO, ${classNameVar}, "id");
89 89 }
90 90  
91 91 @Test
... ... @@ -94,24 +94,24 @@ public class ${table.className}ServiceImplTest extends BaseDbUnitTest {
94 94 ${table.className}DO db${simpleClassName} = randomPojo(${table.className}DO.class);
95 95 ${classNameVar}Mapper.insert(db${simpleClassName});// @Sql: 先插入出一条存在的数据
96 96 // 准备参数
97   - ${sceneEnum.prefixClass}${table.className}UpdateReqVO reqVO = randomPojo(${sceneEnum.prefixClass}${table.className}UpdateReqVO.class, o -> {
  97 + ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class, o -> {
98 98 o.setId(db${simpleClassName}.getId()); // 设置更新的 ID
99 99 });
100 100  
101 101 // 调用
102   - ${classNameVar}Service.update${simpleClassName}(reqVO);
  102 + ${classNameVar}Service.update${simpleClassName}(updateReqVO);
103 103 // 校验是否更新正确
104   - ${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(reqVO.getId()); // 获取最新的
105   - assertPojoEquals(reqVO, ${classNameVar});
  104 + ${table.className}DO ${classNameVar} = ${classNameVar}Mapper.selectById(updateReqVO.getId()); // 获取最新的
  105 + assertPojoEquals(updateReqVO, ${classNameVar});
106 106 }
107 107  
108 108 @Test
109 109 public void testUpdate${simpleClassName}_notExists() {
110 110 // 准备参数
111   - ${sceneEnum.prefixClass}${table.className}UpdateReqVO reqVO = randomPojo(${sceneEnum.prefixClass}${table.className}UpdateReqVO.class);
  111 + ${sceneEnum.prefixClass}${table.className}SaveReqVO updateReqVO = randomPojo(${sceneEnum.prefixClass}${table.className}SaveReqVO.class);
112 112  
113 113 // 调用, 并断言异常
114   - assertServiceException(() -> ${classNameVar}Service.update${simpleClassName}(reqVO), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
  114 + assertServiceException(() -> ${classNameVar}Service.update${simpleClassName}(updateReqVO), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
115 115 }
116 116  
117 117 @Test
... ... @@ -137,6 +137,8 @@ public class ${table.className}ServiceImplTest extends BaseDbUnitTest {
137 137 assertServiceException(() -> ${classNameVar}Service.delete${simpleClassName}(id), ${simpleClassName_underlineCase.toUpperCase()}_NOT_EXISTS);
138 138 }
139 139  
  140 +## 特殊:树表专属逻辑(树不需要分页接口)
  141 +#if ( $table.templateType != 2 )
140 142 @Test
141 143 @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
142 144 public void testGet${simpleClassName}Page() {
... ... @@ -149,11 +151,11 @@ public class ${table.className}ServiceImplTest extends BaseDbUnitTest {
149 151 assertEquals(1, pageResult.getList().size());
150 152 assertPojoEquals(db${simpleClassName}, pageResult.getList().get(0));
151 153 }
152   -
  154 +#else
153 155 @Test
154 156 @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
155 157 public void testGet${simpleClassName}List() {
156   - #getPageCondition("ExportReqVO")
  158 + #getPageCondition("ListReqVO")
157 159  
158 160 // 调用
159 161 List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(reqVO);
... ... @@ -161,5 +163,6 @@ public class ${table.className}ServiceImplTest extends BaseDbUnitTest {
161 163 assertEquals(1, list.size());
162 164 assertPojoEquals(db${simpleClassName}, list.get(0));
163 165 }
  166 +#end
164 167  
165 168 -}
  169 +}
166 170 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/sql/h2.vm
... ... @@ -23,6 +23,8 @@ CREATE TABLE IF NOT EXISTS &quot;${table.tableName.toLowerCase()}&quot; (
23 23 "${column.columnName}" ${dataType} DEFAULT '',
24 24 #elseif (${column.columnName} == 'deleted')
25 25 "deleted" bit NOT NULL DEFAULT FALSE,
  26 + #elseif (${column.columnName} == 'tenantId')
  27 + "tenant_id" bigint NOT NULL DEFAULT 0,
26 28 #else
27 29 "${column.columnName.toLowerCase()}" ${dataType}#if (${column.nullable} == false) NOT NULL#end,
28 30 #end
... ... @@ -32,4 +34,4 @@ CREATE TABLE IF NOT EXISTS &quot;${table.tableName.toLowerCase()}&quot; (
32 34 ) COMMENT '${table.tableComment}';
33 35  
34 36 -- 将该删表 SQL 语句,添加到 yudao-module-${table.moduleName}-biz 模块的 test/resources/sql/clean.sql 文件里
35 37 -DELETE FROM "${table.tableName}";
  38 +DELETE FROM "${table.tableName}";
36 39 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/sql/sql.vm
... ... @@ -5,7 +5,7 @@ INSERT INTO system_menu(
5 5 )
6 6 VALUES (
7 7 '${table.classComment}管理', '', 2, 0, ${table.parentMenuId},
8   - '${simpleClassName_strikeCase}', '', '${table.moduleName}/${classNameVar}/index', 0, '${table.className}'
  8 + '${simpleClassName_strikeCase}', '', '${table.moduleName}/${table.businessName}/index', 0, '${table.className}'
9 9 );
10 10  
11 11 -- 按钮父菜单ID
... ... @@ -25,4 +25,4 @@ VALUES (
25 25 '${table.classComment}${functionName}', '${permissionPrefix}:${functionOps.get($index)}', 3, $foreach.count, @parentId,
26 26 '', '', '', 0
27 27 );
28 28 -#end
  29 +#end
29 30 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm
... ... @@ -15,10 +15,17 @@ export interface ${simpleClassName}VO {
15 15 #end
16 16 }
17 17  
18   -// 查询${table.classComment}列表
  18 +#if ( $table.templateType != 2 )
  19 +// 查询${table.classComment}分页
19 20 export const get${simpleClassName}Page = async (params) => {
20 21 return await request.get({ url: `${baseURL}/page`, params })
21 22 }
  23 +#else
  24 +// 查询${table.classComment}列表
  25 +export const get${simpleClassName}List = async (params) => {
  26 + return await request.get({ url: `${baseURL}/list`, params })
  27 +}
  28 +#end
22 29  
23 30 // 查询${table.classComment}详情
24 31 export const get${simpleClassName} = async (id: number) => {
... ... @@ -44,3 +51,61 @@ export const delete${simpleClassName} = async (id: number) =&gt; {
44 51 export const export${simpleClassName} = async (params) => {
45 52 return await request.download({ url: `${baseURL}/export-excel`, params })
46 53 }
  54 +## 特殊:主子表专属逻辑
  55 +#foreach ($subTable in $subTables)
  56 +#set ($index = $foreach.count - 1)
  57 +#set ($subSimpleClassName = $subSimpleClassNames.get($index))
  58 +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
  59 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  60 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  61 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  62 +#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  63 +#set ($subClassNameVar = $subClassNameVars.get($index))
  64 +
  65 +// ==================== 子表($subTable.classComment) ====================
  66 +## 情况一:MASTER_ERP 时,需要分查询页子表
  67 +#if ( $table.templateType == 11 )
  68 +
  69 +// 获得${subTable.classComment}分页
  70 +export const get${subSimpleClassName}Page = async (params) => {
  71 + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/page`, params })
  72 +}
  73 +## 情况二:非 MASTER_ERP 时,需要列表查询子表
  74 +#else
  75 + #if ( $subTable.subJoinMany )
  76 +
  77 +// 获得${subTable.classComment}列表
  78 +export const get${subSimpleClassName}ListBy${SubJoinColumnName} = async (${subJoinColumn.javaField}) => {
  79 + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} })
  80 +}
  81 + #else
  82 +
  83 +// 获得${subTable.classComment}
  84 +export const get${subSimpleClassName}By${SubJoinColumnName} = async (${subJoinColumn.javaField}) => {
  85 + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} })
  86 +}
  87 + #end
  88 +#end
  89 +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作
  90 +#if ( $table.templateType == 11 )
  91 +// 新增${subTable.classComment}
  92 +export const create${subSimpleClassName} = async (data) => {
  93 + return await request.post({ url: `${baseURL}/${subSimpleClassName_strikeCase}/create`, data })
  94 +}
  95 +
  96 +// 修改${subTable.classComment}
  97 +export const update${subSimpleClassName} = async (data) => {
  98 + return await request.put({ url: `${baseURL}/${subSimpleClassName_strikeCase}/update`, data })
  99 +}
  100 +
  101 +// 删除${subTable.classComment}
  102 +export const delete${subSimpleClassName} = async (id: number) => {
  103 + return await request.delete({ url: `${baseURL}/${subSimpleClassName_strikeCase}/delete?id=` + id })
  104 +}
  105 +
  106 +// 获得${subTable.classComment}
  107 +export const get${subSimpleClassName} = async (id: number) => {
  108 + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get?id=` + id })
  109 +}
  110 +#end
  111 +#end
47 112 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm 0 → 100644
  1 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  2 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +<template>
  5 + <Dialog :title="dialogTitle" v-model="dialogVisible">
  6 + <el-form
  7 + ref="formRef"
  8 + :model="formData"
  9 + :rules="formRules"
  10 + label-width="100px"
  11 + v-loading="formLoading"
  12 + >
  13 +#foreach($column in $subColumns)
  14 + #if ($column.createOperation || $column.updateOperation)
  15 + #set ($dictType = $column.dictType)
  16 + #set ($javaField = $column.javaField)
  17 + #set ($javaType = $column.javaType)
  18 + #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  19 + #set ($comment = $column.columnComment)
  20 + #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
  21 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  22 + #set ($dictMethod = "getIntDictOptions")
  23 + #elseif ($javaType == "String")
  24 + #set ($dictMethod = "getStrDictOptions")
  25 + #elseif ($javaType == "Boolean")
  26 + #set ($dictMethod = "getBoolDictOptions")
  27 + #end
  28 + #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  29 + #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  30 + <el-form-item label="${comment}" prop="${javaField}">
  31 + <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
  32 + </el-form-item>
  33 + #elseif($column.htmlType == "imageUpload")## 图片上传
  34 + <el-form-item label="${comment}" prop="${javaField}">
  35 + <UploadImg v-model="formData.${javaField}" />
  36 + </el-form-item>
  37 + #elseif($column.htmlType == "fileUpload")## 文件上传
  38 + <el-form-item label="${comment}" prop="${javaField}">
  39 + <UploadFile v-model="formData.${javaField}" />
  40 + </el-form-item>
  41 + #elseif($column.htmlType == "editor")## 文本编辑器
  42 + <el-form-item label="${comment}" prop="${javaField}">
  43 + <Editor v-model="formData.${javaField}" height="150px" />
  44 + </el-form-item>
  45 + #elseif($column.htmlType == "select")## 下拉框
  46 + <el-form-item label="${comment}" prop="${javaField}">
  47 + <el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
  48 + #if ("" != $dictType)## 有数据字典
  49 + <el-option
  50 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  51 + :key="dict.value"
  52 + :label="dict.label"
  53 + :value="dict.value"
  54 + />
  55 + #else##没数据字典
  56 + <el-option label="请选择字典生成" value="" />
  57 + #end
  58 + </el-select>
  59 + </el-form-item>
  60 + #elseif($column.htmlType == "checkbox")## 多选框
  61 + <el-form-item label="${comment}" prop="${javaField}">
  62 + <el-checkbox-group v-model="formData.${javaField}">
  63 + #if ("" != $dictType)## 有数据字典
  64 + <el-checkbox
  65 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  66 + :key="dict.value"
  67 + :label="dict.value"
  68 + >
  69 + {{ dict.label }}
  70 + </el-checkbox>
  71 + #else##没数据字典
  72 + <el-checkbox>请选择字典生成</el-checkbox>
  73 + #end
  74 + </el-checkbox-group>
  75 + </el-form-item>
  76 + #elseif($column.htmlType == "radio")## 单选框
  77 + <el-form-item label="${comment}" prop="${javaField}">
  78 + <el-radio-group v-model="formData.${javaField}">
  79 + #if ("" != $dictType)## 有数据字典
  80 + <el-radio
  81 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  82 + :key="dict.value"
  83 + :label="dict.value"
  84 + >
  85 + {{ dict.label }}
  86 + </el-radio>
  87 + #else##没数据字典
  88 + <el-radio label="1">请选择字典生成</el-radio>
  89 + #end
  90 + </el-radio-group>
  91 + </el-form-item>
  92 + #elseif($column.htmlType == "datetime")## 时间框
  93 + <el-form-item label="${comment}" prop="${javaField}">
  94 + <el-date-picker
  95 + v-model="formData.${javaField}"
  96 + type="date"
  97 + value-format="x"
  98 + placeholder="选择${comment}"
  99 + />
  100 + </el-form-item>
  101 + #elseif($column.htmlType == "textarea")## 文本框
  102 + <el-form-item label="${comment}" prop="${javaField}">
  103 + <el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
  104 + </el-form-item>
  105 + #end
  106 + #end
  107 +#end
  108 + </el-form>
  109 + <template #footer>
  110 + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  111 + <el-button @click="dialogVisible = false">取 消</el-button>
  112 + </template>
  113 + </Dialog>
  114 +</template>
  115 +<script setup lang="ts">
  116 +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  117 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
  118 +
  119 +const { t } = useI18n() // 国际化
  120 +const message = useMessage() // 消息弹窗
  121 +
  122 +const dialogVisible = ref(false) // 弹窗的是否展示
  123 +const dialogTitle = ref('') // 弹窗的标题
  124 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  125 +const formType = ref('') // 表单的类型:create - 新增;update - 修改
  126 +const formData = ref({
  127 +#foreach ($column in $subColumns)
  128 + #if ($column.createOperation || $column.updateOperation)
  129 + #if ($column.htmlType == "checkbox")
  130 + $column.javaField: [],
  131 + #else
  132 + $column.javaField: undefined,
  133 + #end
  134 + #end
  135 +#end
  136 +})
  137 +const formRules = reactive({
  138 +#foreach ($column in $subColumns)
  139 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  140 + #set($comment=$column.columnComment)
  141 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
  142 + #end
  143 +#end
  144 +})
  145 +const formRef = ref() // 表单 Ref
  146 +
  147 +/** 打开弹窗 */
  148 +const open = async (type: string, id?: number, ${subJoinColumn.javaField}: number) => {
  149 + dialogVisible.value = true
  150 + dialogTitle.value = t('action.' + type)
  151 + formType.value = type
  152 + resetForm()
  153 + formData.value.${subJoinColumn.javaField} = ${subJoinColumn.javaField}
  154 + // 修改时,设置数据
  155 + if (id) {
  156 + formLoading.value = true
  157 + try {
  158 + formData.value = await ${simpleClassName}Api.get${subSimpleClassName}(id)
  159 + } finally {
  160 + formLoading.value = false
  161 + }
  162 + }
  163 +}
  164 +defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  165 +
  166 +/** 提交表单 */
  167 +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  168 +const submitForm = async () => {
  169 + // 校验表单
  170 + await formRef.value.validate()
  171 + // 提交请求
  172 + formLoading.value = true
  173 + try {
  174 + const data = formData.value
  175 + if (formType.value === 'create') {
  176 + await ${simpleClassName}Api.create${subSimpleClassName}(data)
  177 + message.success(t('common.createSuccess'))
  178 + } else {
  179 + await ${simpleClassName}Api.update${subSimpleClassName}(data)
  180 + message.success(t('common.updateSuccess'))
  181 + }
  182 + dialogVisible.value = false
  183 + // 发送操作成功的事件
  184 + emit('success')
  185 + } finally {
  186 + formLoading.value = false
  187 + }
  188 +}
  189 +
  190 +/** 重置表单 */
  191 +const resetForm = () => {
  192 + formData.value = {
  193 +#foreach ($column in $subColumns)
  194 + #if ($column.createOperation || $column.updateOperation)
  195 + #if ($column.htmlType == "checkbox")
  196 + $column.javaField: [],
  197 + #else
  198 + $column.javaField: undefined,
  199 + #end
  200 + #end
  201 +#end
  202 + }
  203 + formRef.value?.resetFields()
  204 +}
  205 +</script>
0 206 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_inner.vue.vm 0 → 100644
  1 +## 主表的 normal 和 inner 使用相同的 form 表单
  2 +#parse("codegen/vue3/views/components/form_sub_normal.vue.vm")
0 3 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  6 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  7 +<template>
  8 +#if ( $subTable.subJoinMany )## 情况一:一对多,table + form
  9 + <el-form
  10 + ref="formRef"
  11 + :model="formData"
  12 + :rules="formRules"
  13 + v-loading="formLoading"
  14 + label-width="0px"
  15 + :inline-message="true"
  16 + >
  17 + <el-table :data="formData" class="-mt-10px">
  18 + <el-table-column label="序号" type="index" width="100" />
  19 +#foreach($column in $subColumns)
  20 + #if ($column.createOperation || $column.updateOperation)
  21 + #set ($dictType = $column.dictType)
  22 + #set ($javaField = $column.javaField)
  23 + #set ($javaType = $column.javaType)
  24 + #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  25 + #set ($comment = $column.columnComment)
  26 + #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
  27 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  28 + #set ($dictMethod = "getIntDictOptions")
  29 + #elseif ($javaType == "String")
  30 + #set ($dictMethod = "getStrDictOptions")
  31 + #elseif ($javaType == "Boolean")
  32 + #set ($dictMethod = "getBoolDictOptions")
  33 + #end
  34 + #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  35 + #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  36 + <el-table-column label="${comment}" min-width="150">
  37 + <template #default="{ row, $index }">
  38 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  39 + <el-input v-model="row.${javaField}" placeholder="请输入${comment}" />
  40 + </el-form-item>
  41 + </template>
  42 + </el-table-column>
  43 + #elseif($column.htmlType == "imageUpload")## 图片上传
  44 + <el-table-column label="${comment}" min-width="200">
  45 + <template #default="{ row, $index }">
  46 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  47 + <UploadImg v-model="row.${javaField}" />
  48 + </el-form-item>
  49 + </template>
  50 + </el-table-column>
  51 + #elseif($column.htmlType == "fileUpload")## 文件上传
  52 + <el-table-column label="${comment}" min-width="200">
  53 + <template #default="{ row, $index }">
  54 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  55 + <UploadFile v-model="row.${javaField}" />
  56 + </el-form-item>
  57 + </template>
  58 + </el-table-column>
  59 + #elseif($column.htmlType == "editor")## 文本编辑器
  60 + <el-table-column label="${comment}" min-width="400">
  61 + <template #default="{ row, $index }">
  62 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  63 + <Editor v-model="row.${javaField}" height="150px" />
  64 + </el-form-item>
  65 + </template>
  66 + </el-table-column>
  67 + #elseif($column.htmlType == "select")## 下拉框
  68 + <el-table-column label="${comment}" min-width="150">
  69 + <template #default="{ row, $index }">
  70 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  71 + <el-select v-model="row.${javaField}" placeholder="请选择${comment}">
  72 + #if ("" != $dictType)## 有数据字典
  73 + <el-option
  74 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  75 + :key="dict.value"
  76 + :label="dict.label"
  77 + :value="dict.value"
  78 + />
  79 + #else##没数据字典
  80 + <el-option label="请选择字典生成" value="" />
  81 + #end
  82 + </el-select>
  83 + </el-form-item>
  84 + </template>
  85 + </el-table-column>
  86 + #elseif($column.htmlType == "checkbox")## 多选框
  87 + <el-table-column label="${comment}" min-width="150">
  88 + <template #default="{ row, $index }">
  89 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  90 + <el-checkbox-group v-model="row.${javaField}">
  91 + #if ("" != $dictType)## 有数据字典
  92 + <el-checkbox
  93 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  94 + :key="dict.value"
  95 + :label="dict.value"
  96 + >
  97 + {{ dict.label }}
  98 + </el-checkbox>
  99 + #else##没数据字典
  100 + <el-checkbox>请选择字典生成</el-checkbox>
  101 + #end
  102 + </el-checkbox-group>
  103 + </el-form-item>
  104 + </template>
  105 + </el-table-column>
  106 + #elseif($column.htmlType == "radio")## 单选框
  107 + <el-table-column label="${comment}" min-width="150">
  108 + <template #default="{ row, $index }">
  109 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  110 + <el-radio-group v-model="row.${javaField}">
  111 + #if ("" != $dictType)## 有数据字典
  112 + <el-radio
  113 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  114 + :key="dict.value"
  115 + :label="dict.value"
  116 + >
  117 + {{ dict.label }}
  118 + </el-radio>
  119 + #else##没数据字典
  120 + <el-radio label="1">请选择字典生成</el-radio>
  121 + #end
  122 + </el-radio-group>
  123 + </el-form-item>
  124 + </template>
  125 + </el-table-column>
  126 + #elseif($column.htmlType == "datetime")## 时间框
  127 + <el-table-column label="${comment}" min-width="150">
  128 + <template #default="{ row, $index }">
  129 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  130 + <el-date-picker
  131 + v-model="row.${javaField}"
  132 + type="date"
  133 + value-format="x"
  134 + placeholder="选择${comment}"
  135 + />
  136 + </el-form-item>
  137 + </template>
  138 + </el-table-column>
  139 + #elseif($column.htmlType == "textarea")## 文本框
  140 + <el-table-column label="${comment}" min-width="200">
  141 + <template #default="{ row, $index }">
  142 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  143 + <el-input v-model="row.${javaField}" type="textarea" placeholder="请输入${comment}" />
  144 + </el-form-item>
  145 + </template>
  146 + </el-table-column>
  147 + #end
  148 + #end
  149 +#end
  150 + <el-table-column align="center" fixed="right" label="操作" width="60">
  151 + <template #default="{ $index }">
  152 + <el-button @click="handleDelete($index)" link>—</el-button>
  153 + </template>
  154 + </el-table-column>
  155 + </el-table>
  156 + </el-form>
  157 + <el-row justify="center" class="mt-3">
  158 + <el-button @click="handleAdd" round>+ 添加${subTable.classComment}</el-button>
  159 + </el-row>
  160 +#else## 情况二:一对一,form
  161 + <el-form
  162 + ref="formRef"
  163 + :model="formData"
  164 + :rules="formRules"
  165 + label-width="100px"
  166 + v-loading="formLoading"
  167 + >
  168 +#foreach($column in $subColumns)
  169 + #if ($column.createOperation || $column.updateOperation)
  170 + #set ($dictType = $column.dictType)
  171 + #set ($javaField = $column.javaField)
  172 + #set ($javaType = $column.javaType)
  173 + #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  174 + #set ($comment = $column.columnComment)
  175 + #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
  176 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  177 + #set ($dictMethod = "getIntDictOptions")
  178 + #elseif ($javaType == "String")
  179 + #set ($dictMethod = "getStrDictOptions")
  180 + #elseif ($javaType == "Boolean")
  181 + #set ($dictMethod = "getBoolDictOptions")
  182 + #end
  183 + #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  184 + #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  185 + <el-form-item label="${comment}" prop="${javaField}">
  186 + <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
  187 + </el-form-item>
  188 + #elseif($column.htmlType == "imageUpload")## 图片上传
  189 + <el-form-item label="${comment}" prop="${javaField}">
  190 + <UploadImg v-model="formData.${javaField}" />
  191 + </el-form-item>
  192 + #elseif($column.htmlType == "fileUpload")## 文件上传
  193 + <el-form-item label="${comment}" prop="${javaField}">
  194 + <UploadFile v-model="formData.${javaField}" />
  195 + </el-form-item>
  196 + #elseif($column.htmlType == "editor")## 文本编辑器
  197 + <el-form-item label="${comment}" prop="${javaField}">
  198 + <Editor v-model="formData.${javaField}" height="150px" />
  199 + </el-form-item>
  200 + #elseif($column.htmlType == "select")## 下拉框
  201 + <el-form-item label="${comment}" prop="${javaField}">
  202 + <el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
  203 + #if ("" != $dictType)## 有数据字典
  204 + <el-option
  205 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  206 + :key="dict.value"
  207 + :label="dict.label"
  208 + :value="dict.value"
  209 + />
  210 + #else##没数据字典
  211 + <el-option label="请选择字典生成" value="" />
  212 + #end
  213 + </el-select>
  214 + </el-form-item>
  215 + #elseif($column.htmlType == "checkbox")## 多选框
  216 + <el-form-item label="${comment}" prop="${javaField}">
  217 + <el-checkbox-group v-model="formData.${javaField}">
  218 + #if ("" != $dictType)## 有数据字典
  219 + <el-checkbox
  220 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  221 + :key="dict.value"
  222 + :label="dict.value"
  223 + >
  224 + {{ dict.label }}
  225 + </el-checkbox>
  226 + #else##没数据字典
  227 + <el-checkbox>请选择字典生成</el-checkbox>
  228 + #end
  229 + </el-checkbox-group>
  230 + </el-form-item>
  231 + #elseif($column.htmlType == "radio")## 单选框
  232 + <el-form-item label="${comment}" prop="${javaField}">
  233 + <el-radio-group v-model="formData.${javaField}">
  234 + #if ("" != $dictType)## 有数据字典
  235 + <el-radio
  236 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  237 + :key="dict.value"
  238 + :label="dict.value"
  239 + >
  240 + {{ dict.label }}
  241 + </el-radio>
  242 + #else##没数据字典
  243 + <el-radio label="1">请选择字典生成</el-radio>
  244 + #end
  245 + </el-radio-group>
  246 + </el-form-item>
  247 + #elseif($column.htmlType == "datetime")## 时间框
  248 + <el-form-item label="${comment}" prop="${javaField}">
  249 + <el-date-picker
  250 + v-model="formData.${javaField}"
  251 + type="date"
  252 + value-format="x"
  253 + placeholder="选择${comment}"
  254 + />
  255 + </el-form-item>
  256 + #elseif($column.htmlType == "textarea")## 文本框
  257 + <el-form-item label="${comment}" prop="${javaField}">
  258 + <el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
  259 + </el-form-item>
  260 + #end
  261 + #end
  262 +#end
  263 + </el-form>
  264 +#end
  265 +</template>
  266 +<script setup lang="ts">
  267 +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  268 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
  269 +
  270 +const props = defineProps<{
  271 + ${subJoinColumn.javaField}: undefined // ${subJoinColumn.columnComment}(主表的关联字段)
  272 +}>()
  273 +const formLoading = ref(false) // 表单的加载中
  274 +const formData = ref([])
  275 +const formRules = reactive({
  276 +#foreach ($column in $subColumns)
  277 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  278 + #set($comment=$column.columnComment)
  279 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
  280 + #end
  281 +#end
  282 +})
  283 +const formRef = ref() // 表单 Ref
  284 +
  285 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  286 +watch(
  287 + () => props.${subJoinColumn.javaField},
  288 + async (val) => {
  289 + // 1. 重置表单
  290 +#if ( $subTable.subJoinMany )
  291 + formData.value = []
  292 +#else
  293 + formData.value = {
  294 + #foreach ($column in $subColumns)
  295 + #if ($column.createOperation || $column.updateOperation)
  296 + #if ($column.htmlType == "checkbox")
  297 + $column.javaField: [],
  298 + #else
  299 + $column.javaField: undefined,
  300 + #end
  301 + #end
  302 + #end
  303 + }
  304 +#end
  305 + // 2. val 非空,则加载数据
  306 + if (!val) {
  307 + return;
  308 + }
  309 + try {
  310 + formLoading.value = true
  311 +#if ( $subTable.subJoinMany )
  312 + formData.value = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(val)
  313 +#else
  314 + const data = await ${simpleClassName}Api.get${subSimpleClassName}By${SubJoinColumnName}(val)
  315 + if (!data) {
  316 + return
  317 + }
  318 + formData.value = data
  319 +#end
  320 + } finally {
  321 + formLoading.value = false
  322 + }
  323 + },
  324 + { immediate: true }
  325 +)
  326 +#if ( $subTable.subJoinMany )
  327 +
  328 +/** 新增按钮操作 */
  329 +const handleAdd = () => {
  330 + const row = {
  331 +#foreach ($column in $subColumns)
  332 + #if ($column.createOperation || $column.updateOperation)
  333 + #if ($column.htmlType == "checkbox")
  334 + $column.javaField: [],
  335 + #else
  336 + $column.javaField: undefined,
  337 + #end
  338 + #end
  339 +#end
  340 + }
  341 + row.${subJoinColumn.javaField} = props.${subJoinColumn.javaField}
  342 + formData.value.push(row)
  343 +}
  344 +
  345 +/** 删除按钮操作 */
  346 +const handleDelete = (index) => {
  347 + formData.value.splice(index, 1)
  348 +}
  349 +#end
  350 +
  351 +/** 表单校验 */
  352 +const validate = () => {
  353 + return formRef.value.validate()
  354 +}
  355 +
  356 +/** 表单值 */
  357 +const getData = () => {
  358 + return formData.value
  359 +}
  360 +
  361 +defineExpose({ validate, getData })
  362 +</script>
0 363 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  6 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  7 +<template>
  8 + <!-- 列表 -->
  9 + <ContentWrap>
  10 +#if ($table.templateType == 11)
  11 + <el-button
  12 + type="primary"
  13 + plain
  14 + @click="openForm('create')"
  15 + v-hasPermi="['${permissionPrefix}:create']"
  16 + >
  17 + <Icon icon="ep:plus" class="mr-5px" /> 新增
  18 + </el-button>
  19 +#end
  20 + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  21 + #foreach($column in $subColumns)
  22 + #if ($column.listOperationResult)
  23 + #set ($dictType=$column.dictType)
  24 + #set ($javaField = $column.javaField)
  25 + #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  26 + #set ($comment=$column.columnComment)
  27 + #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  28 + #elseif ($column.javaType == "LocalDateTime")## 时间类型
  29 + <el-table-column
  30 + label="${comment}"
  31 + align="center"
  32 + prop="${javaField}"
  33 + :formatter="dateFormatter"
  34 + width="180px"
  35 + />
  36 + #elseif($column.dictType && "" != $column.dictType)## 数据字典
  37 + <el-table-column label="${comment}" align="center" prop="${javaField}">
  38 + <template #default="scope">
  39 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.${column.javaField}" />
  40 + </template>
  41 + </el-table-column>
  42 + #else
  43 + <el-table-column label="${comment}" align="center" prop="${javaField}" />
  44 + #end
  45 + #end
  46 + #end
  47 + #if ($table.templateType == 11)
  48 + <el-table-column label="操作" align="center">
  49 + <template #default="scope">
  50 + <el-button
  51 + link
  52 + type="primary"
  53 + @click="openForm('update', scope.row.id)"
  54 + v-hasPermi="['${permissionPrefix}:update']"
  55 + >
  56 + 编辑
  57 + </el-button>
  58 + <el-button
  59 + link
  60 + type="danger"
  61 + @click="handleDelete(scope.row.id)"
  62 + v-hasPermi="['${permissionPrefix}:delete']"
  63 + >
  64 + 删除
  65 + </el-button>
  66 + </template>
  67 + </el-table-column>
  68 + #end
  69 + </el-table>
  70 + #if ($table.templateType == 11)
  71 + <!-- 分页 -->
  72 + <Pagination
  73 + :total="total"
  74 + v-model:page="queryParams.pageNo"
  75 + v-model:limit="queryParams.pageSize"
  76 + @pagination="getList"
  77 + />
  78 + #end
  79 + </ContentWrap>
  80 +#if ($table.templateType == 11)
  81 + <!-- 表单弹窗:添加/修改 -->
  82 + <${subSimpleClassName}Form ref="formRef" @success="getList" />
  83 +#end
  84 +</template>
  85 +<script setup lang="ts">
  86 +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  87 +import { dateFormatter } from '@/utils/formatTime'
  88 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
  89 +#if ($table.templateType == 11)
  90 +import ${subSimpleClassName}Form from './${subSimpleClassName}Form.vue'
  91 +#end
  92 +
  93 +const { t } = useI18n() // 国际化
  94 +const message = useMessage() // 消息弹窗
  95 +
  96 +const props = defineProps<{
  97 + ${subJoinColumn.javaField}: undefined // ${subJoinColumn.columnComment}(主表的关联字段)
  98 +}>()
  99 +const loading = ref(false) // 列表的加载中
  100 +const list = ref([]) // 列表的数据
  101 +#if ($table.templateType == 11)
  102 +const total = ref(0) // 列表的总页数
  103 +const queryParams = reactive({
  104 + pageNo: 1,
  105 + pageSize: 10,
  106 + ${subJoinColumn.javaField}: undefined
  107 +})
  108 +
  109 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  110 +watch(
  111 + () => props.${subJoinColumn.javaField},
  112 + (val) => {
  113 + queryParams.${subJoinColumn.javaField} = val
  114 + handleQuery()
  115 + },
  116 + { immediate: false }
  117 +)
  118 +#end
  119 +
  120 +/** 查询列表 */
  121 +const getList = async () => {
  122 + loading.value = true
  123 + try {
  124 +#if ($table.templateType == 11)
  125 + const data = await ${simpleClassName}Api.get${subSimpleClassName}Page(queryParams)
  126 + list.value = data.list
  127 + total.value = data.total
  128 +#else
  129 + #if ( $subTable.subJoinMany )
  130 + list.value = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField})
  131 + #else
  132 + const data = await ${simpleClassName}Api.get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField})
  133 + if (!data) {
  134 + return
  135 + }
  136 + list.value.push(data)
  137 + #end
  138 +#end
  139 + } finally {
  140 + loading.value = false
  141 + }
  142 +}
  143 +
  144 +/** 搜索按钮操作 */
  145 +const handleQuery = () => {
  146 + queryParams.pageNo = 1
  147 + getList()
  148 +}
  149 +#if ($table.templateType == 11)
  150 +
  151 +/** 添加/修改操作 */
  152 +const formRef = ref()
  153 +const openForm = (type: string, id?: number) => {
  154 + if (!props.${subJoinColumn.javaField}) {
  155 + message.error('请选择一个${table.classComment}')
  156 + return
  157 + }
  158 + formRef.value.open(type, id, props.${subJoinColumn.javaField})
  159 +}
  160 +
  161 +/** 删除按钮操作 */
  162 +const handleDelete = async (id: number) => {
  163 + try {
  164 + // 删除的二次确认
  165 + await message.delConfirm()
  166 + // 发起删除
  167 + await ${simpleClassName}Api.delete${subSimpleClassName}(id)
  168 + message.success(t('common.delSuccess'))
  169 + // 刷新列表
  170 + await getList()
  171 + } catch {}
  172 +}
  173 +#end
  174 +#if ($table.templateType != 11)
  175 +
  176 +/** 初始化 **/
  177 +onMounted(() => {
  178 + getList()
  179 +})
  180 +#end
  181 +</script>
0 182 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_inner.vue.vm 0 → 100644
  1 +## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点:
  2 +## 1)inner 使用 list 不分页,erp 使用 page 分页
  3 +## 2)erp 支持单个子表的新增、修改、删除,inner 不支持
  4 +#parse("codegen/vue3/views/components/list_sub_erp.vue.vm")
0 5 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm
... ... @@ -7,7 +7,6 @@
7 7 label-width="100px"
8 8 v-loading="formLoading"
9 9 >
10   -#set ($dictMethods = [])## 使用到的 dict 字典方法
11 10 #foreach($column in $columns)
12 11 #if ($column.createOperation || $column.updateOperation)
13 12 #set ($dictType = $column.dictType)
... ... @@ -23,31 +22,41 @@
23 22 #elseif ($javaType == "Boolean")
24 23 #set ($dictMethod = "getBoolDictOptions")
25 24 #end
26   - #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  25 + #if ( $table.templateType == 2 && $column.id == $treeParentColumn.id )
  26 + <el-form-item label="${comment}" prop="${javaField}">
  27 + <el-tree-select
  28 + v-model="formData.${javaField}"
  29 + :data="${classNameVar}Tree"
  30 + #if ($treeNameColumn.javaField == "name")
  31 + :props="defaultProps"
  32 + #else
  33 + :props="{...defaultProps, label: '$treeNameColumn.javaField'}"
  34 + #end
  35 + check-strictly
  36 + default-expand-all
  37 + placeholder="请选择${comment}"
  38 + />
  39 + </el-form-item>
  40 + #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
27 41 <el-form-item label="${comment}" prop="${javaField}">
28 42 <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
29 43 </el-form-item>
30 44 #elseif($column.htmlType == "imageUpload")## 图片上传
31   - #set ($hasImageUploadColumn = true)
32   - <el-form-item label="${comment}">
  45 + <el-form-item label="${comment}" prop="${javaField}">
33 46 <UploadImg v-model="formData.${javaField}" />
34 47 </el-form-item>
35 48 #elseif($column.htmlType == "fileUpload")## 文件上传
36   - #set ($hasFileUploadColumn = true)
37   - <el-form-item label="${comment}">
  49 + <el-form-item label="${comment}" prop="${javaField}">
38 50 <UploadFile v-model="formData.${javaField}" />
39 51 </el-form-item>
40 52 #elseif($column.htmlType == "editor")## 文本编辑器
41   - <el-form-item label="${comment}">
  53 + <el-form-item label="${comment}" prop="${javaField}">
42 54 <Editor v-model="formData.${javaField}" height="150px" />
43 55 </el-form-item>
44 56 #elseif($column.htmlType == "select")## 下拉框
45 57 <el-form-item label="${comment}" prop="${javaField}">
46 58 <el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
47 59 #if ("" != $dictType)## 有数据字典
48   - #if (!$dictMethods.contains($dictMethod))## 如果不存在,则添加到 dictMethods 数组中,后续好 import
49   - #set($ignore = $dictMethods.add($dictMethod) )
50   - #end
51 60 <el-option
52 61 v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
53 62 :key="dict.value"
... ... @@ -63,9 +72,6 @@
63 72 <el-form-item label="${comment}" prop="${javaField}">
64 73 <el-checkbox-group v-model="formData.${javaField}">
65 74 #if ("" != $dictType)## 有数据字典
66   - #if (!$dictMethods.contains($dictMethod))## 如果不存在,则添加到 dictMethods 数组中,后续好 import
67   - #set($ignore = $dictMethods.add($dictMethod) )
68   - #end
69 75 <el-checkbox
70 76 v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
71 77 :key="dict.value"
... ... @@ -82,9 +88,6 @@
82 88 <el-form-item label="${comment}" prop="${javaField}">
83 89 <el-radio-group v-model="formData.${javaField}">
84 90 #if ("" != $dictType)## 有数据字典
85   - #if (!$dictMethods.contains($dictMethod))## 如果不存在,则添加到 dictMethods 数组中,后续好 import
86   - #set($ignore = $dictMethods.add($dictMethod) )
87   - #end
88 91 <el-radio
89 92 v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
90 93 :key="dict.value"
... ... @@ -114,6 +117,21 @@
114 117 #end
115 118 #end
116 119 </el-form>
  120 +## 特殊:主子表专属逻辑
  121 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  122 + <!-- 子表的表单 -->
  123 + <el-tabs v-model="subTabsName">
  124 + #foreach ($subTable in $subTables)
  125 + #set ($index = $foreach.count - 1)
  126 + #set ($subClassNameVar = $subClassNameVars.get($index))
  127 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  128 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  129 + <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
  130 + <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData.id" />
  131 + </el-tab-pane>
  132 + #end
  133 + </el-tabs>
  134 +#end
117 135 <template #footer>
118 136 <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
119 137 <el-button @click="dialogVisible = false">取 消</el-button>
... ... @@ -121,10 +139,18 @@
121 139 </Dialog>
122 140 </template>
123 141 <script setup lang="ts">
124   -#if ($dictMethods.size() > 0)
125   -import { DICT_TYPE#foreach ($dictMethod in $dictMethods), ${dictMethod}#end } from '@/utils/dict'
  142 +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  143 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
  144 +## 特殊:树表专属逻辑
  145 +#if ( $table.templateType == 2 )
  146 +import { defaultProps, handleTree } from '@/utils/tree'
  147 +#end
  148 +## 特殊:主子表专属逻辑
  149 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  150 +#foreach ($subSimpleClassName in $subSimpleClassNames)
  151 +import ${subSimpleClassName}Form from './components/${subSimpleClassName}Form.vue'
  152 +#end
126 153 #end
127   -import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
128 154  
129 155 const { t } = useI18n() // 国际化
130 156 const message = useMessage() // 消息弹窗
... ... @@ -134,37 +160,40 @@ const dialogTitle = ref(&#39;&#39;) // 弹窗的标题
134 160 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
135 161 const formType = ref('') // 表单的类型:create - 新增;update - 修改
136 162 const formData = ref({
137   -#set ($listOperationLastIndex = -1)## 求最后一个需要 , 的地方
138 163 #foreach ($column in $columns)
139 164 #if ($column.createOperation || $column.updateOperation)
140   - #set ($listOperationLastIndex = $foreach.index)
141   - #end
142   -#end
143   -#foreach ($column in $columns)
144   - #if ($column.createOperation || $column.updateOperation)
145   - #if ($column.htmlType == "checkbox")
146   - $column.javaField: []#if($foreach.index < $listOperationLastIndex),#end
147   - #else
148   - $column.javaField: undefined#if($foreach.index < $listOperationLastIndex),#end
149   - #end
  165 + #if ($column.htmlType == "checkbox")
  166 + $column.javaField: [],
  167 + #else
  168 + $column.javaField: undefined,
  169 + #end
150 170 #end
151 171 #end
152 172 })
153 173 const formRules = reactive({
154   -#set ($listOperationLastIndex = -1)## 求最后一个需要 , 的地方
155   -#foreach ($column in $columns)
156   - #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
157   - #set ($listOperationLastIndex = $foreach.index)
158   - #end
159   -#end
160 174 #foreach ($column in $columns)
161 175 #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
162 176 #set($comment=$column.columnComment)
163   - $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }]#if($foreach.index < $listOperationLastIndex),#end
  177 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
164 178 #end
165 179 #end
166 180 })
167 181 const formRef = ref() // 表单 Ref
  182 +## 特殊:树表专属逻辑
  183 +#if ( $table.templateType == 2 )
  184 +const ${classNameVar}Tree = ref() // 树形结构
  185 +#end
  186 +## 特殊:主子表专属逻辑
  187 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  188 +#if ( $subTables && $subTables.size() > 0 )
  189 +
  190 +/** 子表的表单 */
  191 +const subTabsName = ref('$subClassNameVars.get(0)')
  192 +#foreach ($subClassNameVar in $subClassNameVars)
  193 +const ${subClassNameVar}FormRef = ref()
  194 +#end
  195 +#end
  196 +#end
168 197  
169 198 /** 打开弹窗 */
170 199 const open = async (type: string, id?: number) => {
... ... @@ -181,6 +210,10 @@ const open = async (type: string, id?: number) =&gt; {
181 210 formLoading.value = false
182 211 }
183 212 }
  213 +## 特殊:树表专属逻辑
  214 +#if ( $table.templateType == 2 )
  215 + await get${simpleClassName}Tree()
  216 +#end
184 217 }
185 218 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
186 219  
... ... @@ -188,13 +221,38 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
188 221 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
189 222 const submitForm = async () => {
190 223 // 校验表单
191   - if (!formRef) return
192   - const valid = await formRef.value.validate()
193   - if (!valid) return
  224 + await formRef.value.validate()
  225 +## 特殊:主子表专属逻辑
  226 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  227 +#if ( $subTables && $subTables.size() > 0 )
  228 + // 校验子表单
  229 + #foreach ($subTable in $subTables)
  230 + #set ($index = $foreach.count - 1)
  231 + #set ($subClassNameVar = $subClassNameVars.get($index))
  232 + try {
  233 + await ${subClassNameVar}FormRef.value.validate()
  234 + } catch (e) {
  235 + subTabsName.value = '${subClassNameVar}'
  236 + return
  237 + }
  238 + #end
  239 +#end
  240 +#end
194 241 // 提交请求
195 242 formLoading.value = true
196 243 try {
197 244 const data = formData.value as unknown as ${simpleClassName}Api.${simpleClassName}VO
  245 +## 特殊:主子表专属逻辑
  246 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  247 +#if ( $subTables && $subTables.size() > 0 )
  248 + // 拼接子表的数据
  249 + #foreach ($subTable in $subTables)
  250 + #set ($index = $foreach.count - 1)
  251 + #set ($subClassNameVar = $subClassNameVars.get($index))
  252 + data.${subClassNameVar}#if ( $subTable.subJoinMany)s#end = ${subClassNameVar}FormRef.value.getData()
  253 + #end
  254 +#end
  255 +#end
198 256 if (formType.value === 'create') {
199 257 await ${simpleClassName}Api.create${simpleClassName}(data)
200 258 message.success(t('common.createSuccess'))
... ... @@ -213,22 +271,28 @@ const submitForm = async () =&gt; {
213 271 /** 重置表单 */
214 272 const resetForm = () => {
215 273 formData.value = {
216   -#set ($listOperationLastIndex = -1)## 求最后一个需要 , 的地方
217   -#foreach ($column in $columns)
218   - #if ($column.createOperation || $column.updateOperation)
219   - #set ($listOperationLastIndex = $foreach.index)
220   - #end
221   -#end
222 274 #foreach ($column in $columns)
223 275 #if ($column.createOperation || $column.updateOperation)
224 276 #if ($column.htmlType == "checkbox")
225   - $column.javaField: []#if($foreach.index < $listOperationLastIndex),#end
  277 + $column.javaField: [],
226 278 #else
227   - $column.javaField: undefined#if($foreach.index < $listOperationLastIndex),#end
  279 + $column.javaField: undefined,
228 280 #end
229 281 #end
230 282 #end
231 283 }
232 284 formRef.value?.resetFields()
233 285 }
234   -</script>
  286 +## 特殊:树表专属逻辑
  287 +#if ( $table.templateType == 2 )
  288 +
  289 +/** 获得${table.classComment}树 */
  290 +const get${simpleClassName}Tree = async () => {
  291 + ${classNameVar}Tree.value = []
  292 + const data = await ${simpleClassName}Api.get${simpleClassName}List()
  293 + const root: Tree = { id: 0, name: '顶级${table.classComment}', children: [] }
  294 + root.children = handleTree(data, 'id', '${treeParentColumn.javaField}')
  295 + ${classNameVar}Tree.value.push(root)
  296 +}
  297 +#end
  298 +</script>
235 299 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
... ... @@ -8,7 +8,6 @@
8 8 :inline="true"
9 9 label-width="68px"
10 10 >
11   - #set ($dictMethods = [])## 使用到的 dict 字典方法
12 11 #foreach($column in $columns)
13 12 #if ($column.listOperation)
14 13 #set ($dictType = $column.dictType)
... ... @@ -36,20 +35,13 @@
36 35 </el-form-item>
37 36 #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
38 37 <el-form-item label="${comment}" prop="${javaField}">
39   - #if ($javaField.length() + $comment.length() > 8)
40 38 <el-select
41 39 v-model="queryParams.${javaField}"
42 40 placeholder="请选择${comment}"
43 41 clearable
44 42 class="!w-240px"
45 43 >
46   - #else
47   - <el-select v-model="queryParams.${javaField}" placeholder="请选择${comment}" clearable class="!w-240px">
48   - #end
49 44 #if ("" != $dictType)## 设置了 dictType 数据字典的情况
50   - #if (!$dictMethods.contains($dictMethod))## 如果不存在,则添加到 dictMethods 数组中,后续好 import
51   - #set($ignore = $dictMethods.add($dictMethod) )
52   - #end
53 45 <el-option
54 46 v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
55 47 :key="dict.value"
... ... @@ -92,16 +84,12 @@
92 84 <el-form-item>
93 85 <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
94 86 <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
95   - #if ($permissionPrefix.length() <= 12)
96   - <el-button type="primary" @click="openForm('create')" v-hasPermi="['${permissionPrefix}:create']">
97   - #else
98 87 <el-button
99 88 type="primary"
100 89 plain
101 90 @click="openForm('create')"
102 91 v-hasPermi="['${permissionPrefix}:create']"
103 92 >
104   - #end
105 93 <Icon icon="ep:plus" class="mr-5px" /> 新增
106 94 </el-button>
107 95 <el-button
... ... @@ -113,13 +101,61 @@
113 101 >
114 102 <Icon icon="ep:download" class="mr-5px" /> 导出
115 103 </el-button>
  104 +## 特殊:树表专属逻辑
  105 +#if ( $table.templateType == 2 )
  106 + <el-button type="danger" plain @click="toggleExpandAll">
  107 + <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
  108 + </el-button>
  109 +#end
116 110 </el-form-item>
117 111 </el-form>
118 112 </ContentWrap>
119 113  
120 114 <!-- 列表 -->
121 115 <ContentWrap>
  116 +## 特殊:主子表专属逻辑
  117 +#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
  118 + <el-table
  119 + v-loading="loading"
  120 + :data="list"
  121 + :stripe="true"
  122 + :show-overflow-tooltip="true"
  123 + highlight-current-row
  124 + @current-change="handleCurrentChange"
  125 + >
  126 +## 特殊:树表专属逻辑
  127 +#elseif ( $table.templateType == 2 )
  128 + <el-table
  129 + v-loading="loading"
  130 + :data="list"
  131 + :stripe="true"
  132 + :show-overflow-tooltip="true"
  133 + row-key="id"
  134 + :default-expand-all="isExpandAll"
  135 + v-if="refreshTable"
  136 + >
  137 +#else
122 138 <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  139 +#end
  140 +## 特殊:主子表专属逻辑
  141 +#if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
  142 + <!-- 子表的列表 -->
  143 + <el-table-column type="expand">
  144 + <template #default="scope">
  145 + <el-tabs model-value="$subClassNameVars.get(0)">
  146 + #foreach ($subTable in $subTables)
  147 + #set ($index = $foreach.count - 1)
  148 + #set ($subClassNameVar = $subClassNameVars.get($index))
  149 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  150 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  151 + <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
  152 + <${subSimpleClassName}List :${subJoinColumn_strikeCase}="scope.row.id" />
  153 + </el-tab-pane>
  154 + #end
  155 + </el-tabs>
  156 + </template>
  157 + </el-table-column>
  158 +#end
123 159 #foreach($column in $columns)
124 160 #if ($column.listOperationResult)
125 161 #set ($dictType=$column.dictType)
... ... @@ -134,7 +170,7 @@
134 170 :formatter="dateFormatter"
135 171 width="180px"
136 172 />
137   - #elseif("" != $column.dictType)## 数据字典
  173 + #elseif($column.dictType && "" != $column.dictType)## 数据字典
138 174 <el-table-column label="${comment}" align="center" prop="${javaField}">
139 175 <template #default="scope">
140 176 <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.${column.javaField}" />
... ... @@ -177,21 +213,41 @@
177 213  
178 214 <!-- 表单弹窗:添加/修改 -->
179 215 <${simpleClassName}Form ref="formRef" @success="getList" />
  216 +## 特殊:主子表专属逻辑
  217 +#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
  218 + <!-- 子表的列表 -->
  219 + <ContentWrap>
  220 + <el-tabs model-value="$subClassNameVars.get(0)">
  221 + #foreach ($subTable in $subTables)
  222 + #set ($index = $foreach.count - 1)
  223 + #set ($subClassNameVar = $subClassNameVars.get($index))
  224 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  225 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  226 + <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
  227 + <${subSimpleClassName}List :${subJoinColumn_strikeCase}="currentRow.id" />
  228 + </el-tab-pane>
  229 + #end
  230 + </el-tabs>
  231 + </ContentWrap>
  232 +#end
180 233 </template>
181 234  
182 235 <script setup lang="ts">
183   -#if ($dictMethods.size() > 0)
184   -import { DICT_TYPE#foreach ($dictMethod in $dictMethods), ${dictMethod}#end } from '@/utils/dict'
185   -#end
186   -#foreach ($column in $columns)
187   - #if ($column.listOperationResult && $column.htmlType == "datetime")
  236 +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
188 237 import { dateFormatter } from '@/utils/formatTime'
189   - #break
190   - #end
  238 +## 特殊:树表专属逻辑
  239 +#if ( $table.templateType == 2 )
  240 +import { handleTree } from '@/utils/tree'
191 241 #end
192 242 import download from '@/utils/download'
193   -import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
  243 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
194 244 import ${simpleClassName}Form from './${simpleClassName}Form.vue'
  245 +## 特殊:主子表专属逻辑
  246 +#if ( $table.templateType != 10 )
  247 +#foreach ($subSimpleClassName in $subSimpleClassNames)
  248 +import ${subSimpleClassName}List from './components/${subSimpleClassName}List.vue'
  249 +#end
  250 +#end
195 251  
196 252 defineOptions({ name: '${table.className}' })
197 253  
... ... @@ -199,24 +255,24 @@ const message = useMessage() // 消息弹窗
199 255 const { t } = useI18n() // 国际化
200 256  
201 257 const loading = ref(true) // 列表的加载中
202   -const total = ref(0) // 列表的总页数
203 258 const list = ref([]) // 列表的数据
  259 +## 特殊:树表专属逻辑(树不需要分页接口)
  260 +#if ( $table.templateType != 2 )
  261 +const total = ref(0) // 列表的总页数
  262 +#end
204 263 const queryParams = reactive({
  264 +## 特殊:树表专属逻辑(树不需要分页接口)
  265 +#if ( $table.templateType != 2 )
205 266 pageNo: 1,
206 267 pageSize: 10,
207   - #set ($listOperationLastIndex = -1)## 求最后一个需要 , 的地方
208   - #foreach ($column in $columns)
209   - #if ($column.listOperation)
210   - #set ($listOperationLastIndex = $foreach.index)
211   - #end
212   - #end
  268 +#end
213 269 #foreach ($column in $columns)
214 270 #if ($column.listOperation)
215 271 #if ($column.listOperationCondition != 'BETWEEN')
216   - $column.javaField: null#if($foreach.index < $listOperationLastIndex),#end
  272 + $column.javaField: null,
217 273 #end
218 274 #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
219   - $column.javaField: []#if($foreach.index < $listOperationLastIndex),#end
  275 + $column.javaField: [],
220 276 #end
221 277 #end
222 278 #end
... ... @@ -228,9 +284,15 @@ const exportLoading = ref(false) // 导出的加载中
228 284 const getList = async () => {
229 285 loading.value = true
230 286 try {
  287 +## 特殊:树表专属逻辑(树不需要分页接口)
  288 + #if ( $table.templateType == 2 )
  289 + const data = await ${simpleClassName}Api.get${simpleClassName}List(queryParams)
  290 + list.value = handleTree(data, 'id', '${treeParentColumn.javaField}')
  291 + #else
231 292 const data = await ${simpleClassName}Api.get${simpleClassName}Page(queryParams)
232 293 list.value = data.list
233 294 total.value = data.total
  295 + #end
234 296 } finally {
235 297 loading.value = false
236 298 }
... ... @@ -281,9 +343,31 @@ const handleExport = async () =&gt; {
281 343 exportLoading.value = false
282 344 }
283 345 }
  346 +## 特殊:主子表专属逻辑
  347 +#if ( $table.templateType == 11 )
  348 +
  349 +/** 选中行操作 */
  350 +const currentRow = ref({}) // 选中行
  351 +const handleCurrentChange = (row) => {
  352 + currentRow.value = row
  353 +}
  354 +#end
  355 +## 特殊:树表专属逻辑
  356 +#if ( $table.templateType == 2 )
  357 +
  358 +/** 展开/折叠操作 */
  359 +const isExpandAll = ref(true) // 是否展开,默认全部展开
  360 +const refreshTable = ref(true) // 重新渲染表格状态
  361 +const toggleExpandAll = async () => {
  362 + refreshTable.value = false
  363 + isExpandAll.value = !isExpandAll.value
  364 + await nextTick()
  365 + refreshTable.value = true
  366 +}
  367 +#end
284 368  
285 369 /** 初始化 **/
286 370 onMounted(() => {
287 371 getList()
288 372 })
289 373 -</script>
  374 +</script>
290 375 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/data.ts.vm
1 1 import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
2   -#foreach ($column in $columns)
3   - #if ($column.listOperationResult && $column.htmlType == "datetime")
4 2 import { dateFormatter } from '@/utils/formatTime'
5   - #break
6   - #end
7   -#end
8 3  
9 4 // 表单校验
10 5 export const rules = reactive({
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/form.vue.vm
... ... @@ -8,7 +8,7 @@
8 8 </Dialog>
9 9 </template>
10 10 <script setup lang="ts">
11   - import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
  11 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
12 12 import { rules, allSchemas } from './${classNameVar}.data'
13 13 const { t } = useI18n() // 国际化
14 14 const message = useMessage() // 消息弹窗
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/index.vue.vm
... ... @@ -54,7 +54,7 @@
54 54 </template>
55 55 <script setup lang="ts" name="${table.className}">
56 56 import { allSchemas } from './${classNameVar}.data'
57   -import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
  57 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
58 58 import ${simpleClassName}Form from './${simpleClassName}Form.vue'
59 59  
60 60 // tableObject:表格的属性对象,可获得分页大小、条数等属性
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/form.vue.vm
... ... @@ -5,7 +5,7 @@ import { useI18n } from &#39;@/hooks/web/useI18n&#39;
5 5 import { useMessage } from '@/hooks/web/useMessage'
6 6 import { BasicForm, useForm } from '@/components/Form'
7 7 import { BasicModal, useModalInner } from '@/components/Modal'
8   -import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '@/api/${table.moduleName}/${classNameVar}'
  8 +import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
9 9  
10 10 defineOptions({ name: '${table.className}Modal' })
11 11  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben/views/index.vue.vm
... ... @@ -5,7 +5,7 @@ import { useI18n } from &#39;@/hooks/web/useI18n&#39;
5 5 import { useMessage } from '@/hooks/web/useMessage'
6 6 import { useModal } from '@/components/Modal'
7 7 import { useTable } from '@/components/Table'
8   -import { delete${simpleClassName}, export${simpleClassName}, get${simpleClassName}Page } from '@/api/${table.moduleName}/${classNameVar}'
  8 +import { delete${simpleClassName}, export${simpleClassName}, get${simpleClassName}Page } from '@/api/${table.moduleName}/${table.businessName}'
9 9  
10 10 defineOptions({ name: '${table.className}' })
11 11  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/null/.gitkeep deleted
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/dal/mysql/codegen/SchemaColumnMapperTest.java deleted
1   -package cn.iocoder.yudao.module.infra.dal.mysql.codegen;
2   -
3   -import cn.iocoder.yudao.module.tool.dal.dataobject.codegen.SchemaColumnDO;
4   -import cn.iocoder.yudao.module.tool.test.BaseDbUnitTest;
5   -import org.junit.jupiter.api.Test;
6   -
7   -import javax.annotation.Resource;
8   -import java.util.List;
9   -
10   -import static org.junit.jupiter.api.Assertions.assertTrue;
11   -
12   -public class SchemaColumnMapperTest extends BaseDbUnitTest {
13   -
14   - @Resource
15   - private SchemaColumnMapper schemaColumnMapper;
16   -
17   - @Test
18   - public void testSelectListByTableName() {
19   - List<SchemaColumnDO> columns = schemaColumnMapper.selectListByTableName("", "inf_config");
20   - assertTrue(columns.size() > 0);
21   - }
22   -
23   -}
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/dal/package-info.java deleted
1   -/**
2   - * 占位
3   - */
4   -package cn.iocoder.yudao.module.infra.dal;
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenEngineTest.java deleted
1   -package cn.iocoder.yudao.module.infra.service.codegen;
2   -
3   -import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
4   -import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
5   -import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenColumnMapper;
6   -import cn.iocoder.yudao.module.infra.dal.mysql.codegen.CodegenTableMapper;
7   -import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenEngine;
8   -import cn.iocoder.yudao.module.infra.test.BaseDbUnitTest;
9   -import org.junit.jupiter.api.Test;
10   -
11   -import javax.annotation.Resource;
12   -import java.util.List;
13   -import java.util.Map;
14   -
15   -public class CodegenEngineTest extends BaseDbUnitTest {
16   -
17   - @Resource
18   - private CodegenTableMapper codegenTableMapper;
19   - @Resource
20   - private CodegenColumnMapper codegenColumnMapper;
21   -
22   - @Resource
23   - private CodegenEngine codegenEngine;
24   -
25   - @Test
26   - public void testExecute() {
27   - CodegenTableDO table = codegenTableMapper.selectById(20);
28   - List<CodegenColumnDO> columns = codegenColumnMapper.selectListByTableId(table.getId());
29   - Map<String, String> result = codegenEngine.execute(table, columns);
30   - result.forEach((s, s2) -> System.out.println(s2));
31   -// System.out.println(result.get("vue/views/system/test/index.vue"));
32   - }
33   -
34   -}
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenSQLParserTest.java deleted
1   -package cn.iocoder.yudao.module.infra.service.codegen;
2   -
3   -import cn.iocoder.yudao.module.infra.service.codegen.inner.CodegenSQLParser;
4   -import cn.iocoder.yudao.module.infra.test.BaseDbUnitTest;
5   -import org.junit.jupiter.api.Test;
6   -
7   -public class CodegenSQLParserTest extends BaseDbUnitTest {
8   -
9   - @Test
10   - public void testParse() {
11   - String sql = "CREATE TABLE `infra_test_demo` (\n" +
12   - " `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',\n" +
13   - " `name` varchar(100) NOT NULL DEFAULT '' COMMENT '名字',\n" +
14   - " `status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态',\n" +
15   - " `type` tinyint(4) NOT NULL COMMENT '类型',\n" +
16   - " `category` tinyint(4) NOT NULL COMMENT '分类',\n" +
17   - " `remark` varchar(500) DEFAULT NULL COMMENT '备注',\n" +
18   - " `create_by` varchar(64) DEFAULT '' COMMENT '创建者',\n" +
19   - " `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',\n" +
20   - " `update_by` varchar(64) DEFAULT '' COMMENT '更新者',\n" +
21   - " `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',\n" +
22   - " `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',\n" +
23   - " PRIMARY KEY (`id`) USING BTREE\n" +
24   - ") ENGINE=InnoDB AUTO_INCREMENT=108 DEFAULT CHARSET=utf8mb4 COMMENT='字典类型表';";
25   - CodegenSQLParser.parse(sql);
26   - // TODO 芋艿:后续完善断言
27   - }
28   -
29   -}
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/service/codegen/CodegenServiceImplTest.java deleted
1   -package cn.iocoder.yudao.module.infra.service.codegen;
2   -
3   -import cn.iocoder.yudao.module.infra.test.BaseDbUnitTest;
4   -import org.junit.jupiter.api.Test;
5   -
6   -import javax.annotation.Resource;
7   -
8   -class CodegenServiceImplTest extends BaseDbUnitTest {
9   -
10   - @Resource
11   - private CodegenServiceImpl codegenService;
12   -
13   - @Test
14   - public void tetCreateCodegenTable() {
15   - codegenService.createCodegen(0L, "infra_test_demo");
16   -// infraCodegenService.createCodegenTable("infra_codegen_table");
17   -// infraCodegenService.createCodegen("infra_codegen_column");
18   - }
19   -
20   -}
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/service/package-info.java deleted
1   -/**
2   - * 占位
3   - */
4   -package cn.iocoder.yudao.module.infra.service;
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/test/BaseDbAndRedisIntegrationTest.java deleted
1   -package cn.iocoder.yudao.module.infra.test;
2   -
3   -import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration;
4   -import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration;
5   -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
6   -import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
7   -import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration;
8   -import org.redisson.spring.starter.RedissonAutoConfiguration;
9   -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
10   -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
11   -import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
12   -import org.springframework.boot.test.context.SpringBootTest;
13   -import org.springframework.context.annotation.Import;
14   -import org.springframework.test.context.ActiveProfiles;
15   -
16   -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisIntegrationTest.Application.class)
17   -@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件
18   -public class BaseDbAndRedisIntegrationTest {
19   -
20   - @Import({
21   - // DB 配置类
22   - DynamicDataSourceAutoConfiguration.class, // Dynamic Datasource 配置类
23   - YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类
24   - DataSourceAutoConfiguration.class, // Spring DB 自动配置类
25   - DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类
26   - // MyBatis 配置类
27   - YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类
28   - MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类
29   -
30   - // Redis 配置类
31   - RedisAutoConfiguration.class, // Spring Redis 自动配置类
32   - YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
33   - RedissonAutoConfiguration.class, // Redisson 自动高配置类
34   - })
35   - public static class Application {
36   - }
37   -
38   -}
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/test/BaseRedisIntegrationTest.java deleted
1   -package cn.iocoder.yudao.module.infra.test;
2   -
3   -import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration;
4   -import org.redisson.spring.starter.RedissonAutoConfiguration;
5   -import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
6   -import org.springframework.boot.test.context.SpringBootTest;
7   -import org.springframework.context.annotation.Import;
8   -import org.springframework.test.context.ActiveProfiles;
9   -
10   -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisIntegrationTest.Application.class)
11   -@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件
12   -public class BaseRedisIntegrationTest {
13   -
14   - @Import({
15   - // Redis 配置类
16   - RedisAutoConfiguration.class, // Spring Redis 自动配置类
17   - YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类
18   - RedissonAutoConfiguration.class, // Redisson 自动高配置类
19   - })
20   - public static class Application {
21   - }
22   -
23   -}
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.codegen.inner;
  2 +
  3 +import cn.hutool.core.io.FileUtil;
  4 +import cn.hutool.core.io.IoUtil;
  5 +import cn.hutool.core.io.resource.ResourceUtil;
  6 +import cn.hutool.core.map.MapUtil;
  7 +import cn.hutool.core.util.StrUtil;
  8 +import cn.hutool.core.util.ZipUtil;
  9 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  10 +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
  13 +import cn.iocoder.yudao.module.infra.enums.codegen.*;
  14 +import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
  15 +import org.apache.ibatis.type.JdbcType;
  16 +import org.junit.jupiter.api.BeforeEach;
  17 +import org.junit.jupiter.api.Test;
  18 +import org.mockito.InjectMocks;
  19 +import org.mockito.Spy;
  20 +
  21 +import java.io.ByteArrayInputStream;
  22 +import java.io.ByteArrayOutputStream;
  23 +import java.util.*;
  24 +
  25 +import static org.junit.jupiter.api.Assertions.assertEquals;
  26 +import static org.junit.jupiter.api.Assertions.assertTrue;
  27 +
  28 +/**
  29 + * {@link CodegenEngine} 的单元测试
  30 + *
  31 + * @author 芋道源码
  32 + */
  33 +public class CodegenEngineTest extends BaseMockitoUnitTest {
  34 +
  35 + @InjectMocks
  36 + private CodegenEngine codegenEngine;
  37 +
  38 + @Spy
  39 + private CodegenProperties codegenProperties = new CodegenProperties()
  40 + .setBasePackage("cn.iocoder.yudao");
  41 +
  42 + @BeforeEach
  43 + public void setUp() {
  44 + codegenEngine.initGlobalBindingMap();
  45 + }
  46 +
  47 + @Test
  48 + public void testExecute_vue3_one() {
  49 + // 准备参数
  50 + CodegenTableDO table = getTable("student")
  51 + .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
  52 + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
  53 + List<CodegenColumnDO> columns = getColumnList("student");
  54 +
  55 + // 调用
  56 + Map<String, String> result = codegenEngine.execute(table, columns, null, null);
  57 + // 断言
  58 + assertResult(result, "codegen/vue3_one");
  59 +// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one");
  60 + }
  61 +
  62 + @Test
  63 + public void testExecute_vue3_tree() {
  64 + // 准备参数
  65 + CodegenTableDO table = getTable("category")
  66 + .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
  67 + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType());
  68 + List<CodegenColumnDO> columns = getColumnList("category");
  69 +
  70 + // 调用
  71 + Map<String, String> result = codegenEngine.execute(table, columns, null, null);
  72 + // 断言
  73 + assertResult(result, "codegen/vue3_tree");
  74 +// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree");
  75 +// writeFile(result, "/Users/yunai/test/demo66.zip");
  76 + }
  77 +
  78 + @Test
  79 + public void testExecute_vue3_master_normal() {
  80 + testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "codegen/vue3_master_normal");
  81 + }
  82 +
  83 + @Test
  84 + public void testExecute_vue3_master_erp() {
  85 + testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_ERP, "codegen/vue3_master_erp");
  86 + }
  87 +
  88 + @Test
  89 + public void testExecute_vue3_master_inner() {
  90 + testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_INNER, "codegen/vue3_master_inner");
  91 + }
  92 +
  93 + private void testExecute_vue3_master(CodegenTemplateTypeEnum templateType,
  94 + String path) {
  95 + // 准备参数
  96 + CodegenTableDO table = getTable("student")
  97 + .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
  98 + .setTemplateType(templateType.getType());
  99 + List<CodegenColumnDO> columns = getColumnList("student");
  100 + // 准备参数(子表)
  101 + CodegenTableDO contactTable = getTable("contact")
  102 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  103 + .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
  104 + .setSubJoinColumnId(100L).setSubJoinMany(true);
  105 + List<CodegenColumnDO> contactColumns = getColumnList("contact");
  106 + // 准备参数(班主任)
  107 + CodegenTableDO teacherTable = getTable("teacher")
  108 + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
  109 + .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
  110 + .setSubJoinColumnId(200L).setSubJoinMany(false);
  111 + List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
  112 +
  113 + // 调用
  114 + Map<String, String> result = codegenEngine.execute(table, columns,
  115 + Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
  116 + // 断言
  117 + assertResult(result, path);
  118 +// writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/" + path);
  119 +// writeFile(result, "/Users/yunai/test/demo11.zip");
  120 + }
  121 +
  122 + private static CodegenTableDO getTable(String name) {
  123 + String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
  124 + return JsonUtils.parseObject(content, "table", CodegenTableDO.class);
  125 + }
  126 +
  127 + private static List<CodegenColumnDO> getColumnList(String name) {
  128 + String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
  129 + List<CodegenColumnDO> list = JsonUtils.parseArray(content, "columns", CodegenColumnDO.class);
  130 + list.forEach(column -> {
  131 + if (column.getNullable() == null) {
  132 + column.setNullable(false);
  133 + }
  134 + if (column.getCreateOperation() == null) {
  135 + column.setCreateOperation(false);
  136 + }
  137 + if (column.getUpdateOperation() == null) {
  138 + column.setUpdateOperation(false);
  139 + }
  140 + if (column.getListOperation() == null) {
  141 + column.setListOperation(false);
  142 + }
  143 + if (column.getListOperationResult() == null) {
  144 + column.setListOperationResult(false);
  145 + }
  146 + });
  147 + return list;
  148 + }
  149 +
  150 + @SuppressWarnings("rawtypes")
  151 + private static void assertResult(Map<String, String> result, String path) {
  152 + String assertContent = ResourceUtil.readUtf8Str(path + "/assert.json");
  153 + List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class);
  154 + assertEquals(asserts.size(), result.size());
  155 + // 校验每个文件
  156 + asserts.forEach(assertMap -> {
  157 + String contentPath = (String) assertMap.get("contentPath");
  158 + String filePath = (String) assertMap.get("filePath");
  159 + String content = ResourceUtil.readUtf8Str(path + "/" + contentPath);
  160 + assertEquals(content, result.get(filePath), filePath + ":不匹配");
  161 + });
  162 + }
  163 +
  164 + // ==================== 调试专用 ====================
  165 +
  166 + /**
  167 + * 【调试使用】将生成的代码,写入到文件
  168 + *
  169 + * @param result 生成的代码
  170 + * @param path 写入文件的路径
  171 + */
  172 + private void writeFile(Map<String, String> result, String path) {
  173 + // 生成压缩包
  174 + String[] paths = result.keySet().toArray(new String[0]);
  175 + ByteArrayInputStream[] ins = result.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
  176 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  177 + ZipUtil.zip(outputStream, paths, ins);
  178 + // 写入文件
  179 + FileUtil.writeBytes(outputStream.toByteArray(), path);
  180 + }
  181 +
  182 + /**
  183 + * 【调试使用】将生成的结果,写入到文件
  184 + *
  185 + * @param result 生成的代码
  186 + * @param basePath 写入文件的路径(绝对路径)
  187 + */
  188 + private void writeResult(Map<String, String> result, String basePath) {
  189 + // 写入文件内容
  190 + List<Map<String, String>> asserts = new ArrayList<>();
  191 + result.forEach((filePath, fileContent) -> {
  192 + String lastFilePath = StrUtil.subAfter(filePath, '/', true);
  193 + String contentPath = StrUtil.subAfter(lastFilePath, '.', true)
  194 + + '/' + StrUtil.subBefore(lastFilePath, '.', true);
  195 + asserts.add(MapUtil.<String, String>builder().put("filePath", filePath)
  196 + .put("contentPath", contentPath).build());
  197 + FileUtil.writeUtf8String(fileContent, basePath + "/" + contentPath);
  198 + });
  199 + // 写入 assert.json 文件
  200 + FileUtil.writeUtf8String(JsonUtils.toJsonPrettyString(asserts), basePath +"/assert.json");
  201 + }
  202 +
  203 +}
... ...
yudao-module-infra/yudao-module-infra-biz/src/test-integration/java/cn/iocoder/yudao/module/infra/dal/mysql/package-info.java renamed to yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/package-info.java
1 1 /**
2   - * 占位
  2 + * 占位,无其它作用
3 3 */
4   -package cn.iocoder.yudao.module.infra.dal.mysql;
  4 +package cn.iocoder.yudao.module.infra.service.codegen;
5 5 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/test/TestDemoServiceImplTest.java deleted
1   -package cn.iocoder.yudao.module.infra.service.test;
2   -
3   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
6   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoCreateReqVO;
7   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoExportReqVO;
8   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoPageReqVO;
9   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoUpdateReqVO;
10   -import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
11   -import cn.iocoder.yudao.module.infra.dal.mysql.test.TestDemoMapper;
12   -import org.junit.jupiter.api.Test;
13   -import org.springframework.context.annotation.Import;
14   -
15   -import javax.annotation.Resource;
16   -import java.time.LocalDateTime;
17   -import java.util.List;
18   -
19   -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
20   -import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
21   -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
22   -import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
23   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
24   -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
25   -import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.TEST_DEMO_NOT_EXISTS;
26   -import static org.junit.jupiter.api.Assertions.*;
27   -
28   -/**
29   - * {@link TestDemoServiceImpl} 的单元测试类
30   - *
31   - * @author 芋道源码
32   - */
33   -@Import(TestDemoServiceImpl.class)
34   -public class TestDemoServiceImplTest extends BaseDbUnitTest {
35   -
36   - @Resource
37   - private TestDemoServiceImpl testDemoService;
38   -
39   - @Resource
40   - private TestDemoMapper testDemoMapper;
41   -
42   - @Test
43   - public void testCreateTestDemo_success() {
44   - // 准备参数
45   - TestDemoCreateReqVO reqVO = randomPojo(TestDemoCreateReqVO.class);
46   -
47   - // 调用
48   - Long testDemoId = testDemoService.createTestDemo(reqVO);
49   - // 断言
50   - assertNotNull(testDemoId);
51   - // 校验记录的属性是否正确
52   - TestDemoDO testDemo = testDemoMapper.selectById(testDemoId);
53   - assertPojoEquals(reqVO, testDemo);
54   - }
55   -
56   - @Test
57   - public void testUpdateTestDemo_success() {
58   - // mock 数据
59   - TestDemoDO dbTestDemo = randomPojo(TestDemoDO.class);
60   - testDemoMapper.insert(dbTestDemo);// @Sql: 先插入出一条存在的数据
61   - // 准备参数
62   - TestDemoUpdateReqVO reqVO = randomPojo(TestDemoUpdateReqVO.class, o -> {
63   - o.setId(dbTestDemo.getId()); // 设置更新的 ID
64   - });
65   -
66   - // 调用
67   - testDemoService.updateTestDemo(reqVO);
68   - // 校验是否更新正确
69   - TestDemoDO testDemo = testDemoMapper.selectById(reqVO.getId()); // 获取最新的
70   - assertPojoEquals(reqVO, testDemo);
71   - }
72   -
73   - @Test
74   - public void testUpdateTestDemo_notExists() {
75   - // 准备参数
76   - TestDemoUpdateReqVO reqVO = randomPojo(TestDemoUpdateReqVO.class);
77   -
78   - // 调用, 并断言异常
79   - assertServiceException(() -> testDemoService.updateTestDemo(reqVO), TEST_DEMO_NOT_EXISTS);
80   - }
81   -
82   - @Test
83   - public void testDeleteTestDemo_success() {
84   - // mock 数据
85   - TestDemoDO dbTestDemo = randomPojo(TestDemoDO.class);
86   - testDemoMapper.insert(dbTestDemo);// @Sql: 先插入出一条存在的数据
87   - // 准备参数
88   - Long id = dbTestDemo.getId();
89   -
90   - // 调用
91   - testDemoService.deleteTestDemo(id);
92   - // 校验数据不存在了
93   - assertNull(testDemoMapper.selectById(id));
94   - }
95   -
96   - @Test
97   - public void testDeleteTestDemo_notExists() {
98   - // 准备参数
99   - Long id = randomLongId();
100   -
101   - // 调用, 并断言异常
102   - assertServiceException(() -> testDemoService.deleteTestDemo(id), TEST_DEMO_NOT_EXISTS);
103   - }
104   -
105   - @Test
106   - public void testGetTestDemoPage() {
107   - // mock 数据
108   - TestDemoDO dbTestDemo = randomPojo(TestDemoDO.class, o -> { // 等会查询到
109   - o.setName("芋道源码");
110   - o.setStatus(CommonStatusEnum.ENABLE.getStatus());
111   - o.setType(1);
112   - o.setCategory(2);
113   - o.setRemark("哈哈哈");
114   - o.setCreateTime(buildTime(2021, 11, 11));
115   - });
116   - testDemoMapper.insert(dbTestDemo);
117   - // 测试 name 不匹配
118   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setName("不匹配")));
119   - // 测试 status 不匹配
120   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
121   - // 测试 type 不匹配
122   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setType(2)));
123   - // 测试 category 不匹配
124   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setCategory(1)));
125   - // 测试 remark 不匹配
126   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setRemark("呵呵呵")));
127   - // 测试 createTime 不匹配
128   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setCreateTime(buildTime(2021, 12, 12))));
129   - // 准备参数
130   - TestDemoPageReqVO reqVO = new TestDemoPageReqVO();
131   - reqVO.setName("芋道");
132   - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
133   - reqVO.setType(1);
134   - reqVO.setCategory(2);
135   - reqVO.setRemark("哈哈哈");
136   - reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 10),buildTime(2021, 11, 12)}));
137   -
138   - // 调用
139   - PageResult<TestDemoDO> pageResult = testDemoService.getTestDemoPage(reqVO);
140   - // 断言
141   - assertEquals(1, pageResult.getTotal());
142   - assertEquals(1, pageResult.getList().size());
143   - assertPojoEquals(dbTestDemo, pageResult.getList().get(0));
144   - }
145   -
146   - @Test
147   - public void testGetTestDemoList() {
148   - // mock 数据
149   - TestDemoDO dbTestDemo = randomPojo(TestDemoDO.class, o -> { // 等会查询到
150   - o.setName("芋道源码");
151   - o.setStatus(CommonStatusEnum.ENABLE.getStatus());
152   - o.setType(1);
153   - o.setCategory(2);
154   - o.setRemark("哈哈哈");
155   - o.setCreateTime(buildTime(2021, 11, 11));
156   - });
157   - testDemoMapper.insert(dbTestDemo);
158   - // 测试 name 不匹配
159   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setName("不匹配")));
160   - // 测试 status 不匹配
161   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
162   - // 测试 type 不匹配
163   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setType(2)));
164   - // 测试 category 不匹配
165   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setCategory(1)));
166   - // 测试 remark 不匹配
167   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setRemark("呵呵呵")));
168   - // 测试 createTime 不匹配
169   - testDemoMapper.insert(cloneIgnoreId(dbTestDemo, o -> o.setCreateTime(buildTime(2021, 12, 12))));
170   - // 准备参数
171   - TestDemoExportReqVO reqVO = new TestDemoExportReqVO();
172   - reqVO.setName("芋道");
173   - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
174   - reqVO.setType(1);
175   - reqVO.setCategory(2);
176   - reqVO.setRemark("哈哈哈");
177   - reqVO.setCreateTime((new LocalDateTime[]{buildTime(2021, 11, 10),buildTime(2021, 11, 12)}));
178   -
179   - // 调用
180   - List<TestDemoDO> list = testDemoService.getTestDemoList(reqVO);
181   - // 断言
182   - assertEquals(1, list.size());
183   - assertPojoEquals(dbTestDemo, list.get(0));
184   - }
185   -
186   -}
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/category.json 0 → 100644
  1 +{
  2 + "table": {
  3 + "id": 10,
  4 + "scene" : 1,
  5 + "parentMenuId" : 888,
  6 + "tableName" : "infra_category",
  7 + "tableComment" : "分类表",
  8 + "moduleName" : "infra",
  9 + "businessName" : "demo",
  10 + "className" : "InfraCategory",
  11 + "classComment" : "分类",
  12 + "author" : "芋道源码",
  13 + "treeParentColumnId" : 22,
  14 + "treeNameColumnId" : 11
  15 + },
  16 + "columns": [ {
  17 + "columnName" : "id",
  18 + "dataType" : "BIGINT",
  19 + "columnComment" : "编号",
  20 + "primaryKey" : true,
  21 + "autoIncrement" : true,
  22 + "javaType" : "Long",
  23 + "javaField" : "id",
  24 + "example" : "1024",
  25 + "updateOperation" : true,
  26 + "listOperationResult" : true
  27 + }, {
  28 + "id" : 11,
  29 + "columnName" : "name",
  30 + "dataType" : "VARCHAR",
  31 + "columnComment" : "名字",
  32 + "javaType" : "String",
  33 + "javaField" : "name",
  34 + "example" : "芋头",
  35 + "createOperation" : true,
  36 + "updateOperation" : true,
  37 + "listOperation" : true,
  38 + "listOperationCondition" : "LIKE",
  39 + "listOperationResult" : true,
  40 + "htmlType" : "input"
  41 + }, {
  42 + "id" : 22,
  43 + "columnName" : "description",
  44 + "dataType" : "VARCHAR",
  45 + "columnComment" : "父编号",
  46 + "javaType" : "Long",
  47 + "javaField" : "parentId",
  48 + "example" : "2048",
  49 + "createOperation" : true,
  50 + "updateOperation" : true,
  51 + "listOperationResult" : true
  52 + } ]
  53 +}
0 54 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/contact.json 0 → 100644
  1 +{
  2 + "table": {
  3 + "scene" : 1,
  4 + "tableName" : "infra_student_contact",
  5 + "tableComment" : "学生联系人表",
  6 + "moduleName" : "infra",
  7 + "businessName" : "demo",
  8 + "className" : "InfraStudentContact",
  9 + "classComment" : "学生联系人",
  10 + "author" : "芋道源码"
  11 + },
  12 + "columns": [ {
  13 + "columnName" : "id",
  14 + "dataType" : "BIGINT",
  15 + "columnComment" : "编号",
  16 + "primaryKey" : true,
  17 + "autoIncrement" : true,
  18 + "javaType" : "Long",
  19 + "javaField" : "id",
  20 + "example" : "1024",
  21 + "updateOperation" : true,
  22 + "listOperationResult" : true
  23 + }, {
  24 + "id" : 100,
  25 + "columnName" : "student_id",
  26 + "dataType" : "BIGINT",
  27 + "columnComment" : "学生编号",
  28 + "javaType" : "Long",
  29 + "javaField" : "studentId",
  30 + "example" : "2048",
  31 + "createOperation" : true,
  32 + "updateOperation" : true,
  33 + "listOperationResult" : true
  34 + }, {
  35 + "columnName" : "name",
  36 + "dataType" : "VARCHAR",
  37 + "columnComment" : "名字",
  38 + "javaType" : "String",
  39 + "javaField" : "name",
  40 + "example" : "芋头",
  41 + "createOperation" : true,
  42 + "updateOperation" : true,
  43 + "listOperation" : true,
  44 + "listOperationCondition" : "LIKE",
  45 + "listOperationResult" : true,
  46 + "htmlType" : "input"
  47 + }, {
  48 + "columnName" : "description",
  49 + "dataType" : "VARCHAR",
  50 + "columnComment" : "简介",
  51 + "javaType" : "String",
  52 + "javaField" : "description",
  53 + "example" : "我是介绍",
  54 + "createOperation" : true,
  55 + "updateOperation" : true,
  56 + "listOperationResult" : true,
  57 + "htmlType" : "textarea"
  58 + }, {
  59 + "columnName" : "birthday",
  60 + "dataType" : "DATE",
  61 + "columnComment" : "出生日期",
  62 + "javaType" : "LocalDateTime",
  63 + "javaField" : "birthday",
  64 + "createOperation" : true,
  65 + "updateOperation" : true,
  66 + "listOperation" : true,
  67 + "listOperationCondition" : "=",
  68 + "listOperationResult" : true,
  69 + "htmlType" : "datetime"
  70 + }, {
  71 + "columnName" : "sex",
  72 + "dataType" : "INTEGER",
  73 + "columnComment" : "性别",
  74 + "javaType" : "Integer",
  75 + "javaField" : "sex",
  76 + "dictType" : "system_user_sex",
  77 + "example" : "1",
  78 + "createOperation" : true,
  79 + "updateOperation" : true,
  80 + "listOperation" : true,
  81 + "listOperationCondition" : "=",
  82 + "listOperationResult" : true,
  83 + "htmlType" : "select"
  84 + }, {
  85 + "columnName" : "enabled",
  86 + "dataType" : "BOOLEAN",
  87 + "columnComment" : "是否有效",
  88 + "javaType" : "Boolean",
  89 + "javaField" : "enabled",
  90 + "dictType" : "infra_boolean_string",
  91 + "example" : "true",
  92 + "createOperation" : true,
  93 + "updateOperation" : true,
  94 + "listOperation" : true,
  95 + "listOperationCondition" : "=",
  96 + "listOperationResult" : true,
  97 + "htmlType" : "radio"
  98 + }, {
  99 + "columnName" : "avatar",
  100 + "dataType" : "VARCHAR",
  101 + "columnComment" : "头像",
  102 + "javaType" : "String",
  103 + "javaField" : "avatar",
  104 + "example" : "https://www.iocoder.cn/1.png",
  105 + "createOperation" : true,
  106 + "updateOperation" : true,
  107 + "listOperationResult" : true,
  108 + "htmlType" : "imageUpload"
  109 + }, {
  110 + "columnName" : "video",
  111 + "dataType" : "VARCHAR",
  112 + "columnComment" : "附件",
  113 + "nullable" : true,
  114 + "javaType" : "String",
  115 + "javaField" : "video",
  116 + "example" : "https://www.iocoder.cn/1.mp4",
  117 + "createOperation" : true,
  118 + "updateOperation" : true,
  119 + "listOperationResult" : true,
  120 + "htmlType" : "fileUpload"
  121 + }, {
  122 + "columnName" : "memo",
  123 + "dataType" : "VARCHAR",
  124 + "columnComment" : "备注",
  125 + "javaType" : "String",
  126 + "javaField" : "memo",
  127 + "example" : "我是备注",
  128 + "createOperation" : true,
  129 + "updateOperation" : true,
  130 + "listOperationResult" : true,
  131 + "htmlType" : "editor"
  132 + }, {
  133 + "columnName" : "create_time",
  134 + "dataType" : "DATE",
  135 + "columnComment" : "创建时间",
  136 + "nullable" : true,
  137 + "javaType" : "LocalDateTime",
  138 + "javaField" : "createTime",
  139 + "listOperation" : true,
  140 + "listOperationCondition" : "BETWEEN",
  141 + "listOperationResult" : true,
  142 + "htmlType" : "datetime"
  143 + } ]
  144 +}
0 145 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/student.json 0 → 100644
  1 +{
  2 + "table": {
  3 + "id": 1,
  4 + "scene" : 1,
  5 + "parentMenuId" : 888,
  6 + "tableName" : "infra_student",
  7 + "tableComment" : "学生表",
  8 + "moduleName" : "infra",
  9 + "businessName" : "demo",
  10 + "className" : "InfraStudent",
  11 + "classComment" : "学生",
  12 + "author" : "芋道源码"
  13 + },
  14 + "columns": [ {
  15 + "id" : 100,
  16 + "columnName" : "id",
  17 + "dataType" : "BIGINT",
  18 + "columnComment" : "编号",
  19 + "primaryKey" : true,
  20 + "autoIncrement" : true,
  21 + "javaType" : "Long",
  22 + "javaField" : "id",
  23 + "example" : "1024",
  24 + "updateOperation" : true,
  25 + "listOperationResult" : true
  26 + }, {
  27 + "columnName" : "name",
  28 + "dataType" : "VARCHAR",
  29 + "columnComment" : "名字",
  30 + "javaType" : "String",
  31 + "javaField" : "name",
  32 + "example" : "芋头",
  33 + "createOperation" : true,
  34 + "updateOperation" : true,
  35 + "listOperation" : true,
  36 + "listOperationCondition" : "LIKE",
  37 + "listOperationResult" : true,
  38 + "htmlType" : "input"
  39 + }, {
  40 + "columnName" : "description",
  41 + "dataType" : "VARCHAR",
  42 + "columnComment" : "简介",
  43 + "javaType" : "String",
  44 + "javaField" : "description",
  45 + "example" : "我是介绍",
  46 + "createOperation" : true,
  47 + "updateOperation" : true,
  48 + "listOperationResult" : true,
  49 + "htmlType" : "textarea"
  50 + }, {
  51 + "columnName" : "birthday",
  52 + "dataType" : "DATE",
  53 + "columnComment" : "出生日期",
  54 + "javaType" : "LocalDateTime",
  55 + "javaField" : "birthday",
  56 + "createOperation" : true,
  57 + "updateOperation" : true,
  58 + "listOperation" : true,
  59 + "listOperationCondition" : "=",
  60 + "listOperationResult" : true,
  61 + "htmlType" : "datetime"
  62 + }, {
  63 + "columnName" : "sex",
  64 + "dataType" : "INTEGER",
  65 + "columnComment" : "性别",
  66 + "javaType" : "Integer",
  67 + "javaField" : "sex",
  68 + "dictType" : "system_user_sex",
  69 + "example" : "1",
  70 + "createOperation" : true,
  71 + "updateOperation" : true,
  72 + "listOperation" : true,
  73 + "listOperationCondition" : "=",
  74 + "listOperationResult" : true,
  75 + "htmlType" : "select"
  76 + }, {
  77 + "columnName" : "enabled",
  78 + "dataType" : "BOOLEAN",
  79 + "columnComment" : "是否有效",
  80 + "javaType" : "Boolean",
  81 + "javaField" : "enabled",
  82 + "dictType" : "infra_boolean_string",
  83 + "example" : "true",
  84 + "createOperation" : true,
  85 + "updateOperation" : true,
  86 + "listOperation" : true,
  87 + "listOperationCondition" : "=",
  88 + "listOperationResult" : true,
  89 + "htmlType" : "radio"
  90 + }, {
  91 + "columnName" : "avatar",
  92 + "dataType" : "VARCHAR",
  93 + "columnComment" : "头像",
  94 + "javaType" : "String",
  95 + "javaField" : "avatar",
  96 + "example" : "https://www.iocoder.cn/1.png",
  97 + "createOperation" : true,
  98 + "updateOperation" : true,
  99 + "listOperationResult" : true,
  100 + "htmlType" : "imageUpload"
  101 + }, {
  102 + "columnName" : "video",
  103 + "dataType" : "VARCHAR",
  104 + "columnComment" : "附件",
  105 + "javaType" : "String",
  106 + "javaField" : "video",
  107 + "example" : "https://www.iocoder.cn/1.mp4",
  108 + "createOperation" : true,
  109 + "updateOperation" : true,
  110 + "listOperationResult" : true,
  111 + "htmlType" : "fileUpload"
  112 + }, {
  113 + "columnName" : "memo",
  114 + "dataType" : "VARCHAR",
  115 + "columnComment" : "备注",
  116 + "javaType" : "String",
  117 + "javaField" : "memo",
  118 + "example" : "我是备注",
  119 + "createOperation" : true,
  120 + "updateOperation" : true,
  121 + "listOperationResult" : true,
  122 + "htmlType" : "editor"
  123 + }, {
  124 + "columnName" : "create_time",
  125 + "dataType" : "DATE",
  126 + "columnComment" : "创建时间",
  127 + "nullable" : true,
  128 + "javaType" : "LocalDateTime",
  129 + "javaField" : "createTime",
  130 + "listOperation" : true,
  131 + "listOperationCondition" : "BETWEEN",
  132 + "listOperationResult" : true,
  133 + "htmlType" : "datetime"
  134 + } ]
  135 +}
0 136 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/table/teacher.json 0 → 100644
  1 +{
  2 + "table": {
  3 + "scene" : 1,
  4 + "tableName" : "infra_student_teacher",
  5 + "tableComment" : "学生班主任表",
  6 + "moduleName" : "infra",
  7 + "businessName" : "demo",
  8 + "className" : "InfraStudentTeacher",
  9 + "classComment" : "学生班主任",
  10 + "author" : "芋道源码"
  11 + },
  12 + "columns": [ {
  13 + "columnName" : "id",
  14 + "dataType" : "BIGINT",
  15 + "columnComment" : "编号",
  16 + "primaryKey" : true,
  17 + "autoIncrement" : true,
  18 + "javaType" : "Long",
  19 + "javaField" : "id",
  20 + "example" : "1024",
  21 + "updateOperation" : true,
  22 + "listOperationResult" : true
  23 + }, {
  24 + "id" : 200,
  25 + "columnName" : "student_id",
  26 + "dataType" : "BIGINT",
  27 + "columnComment" : "学生编号",
  28 + "javaType" : "Long",
  29 + "javaField" : "studentId",
  30 + "example" : "2048",
  31 + "createOperation" : true,
  32 + "updateOperation" : true,
  33 + "listOperationResult" : true
  34 + }, {
  35 + "columnName" : "name",
  36 + "dataType" : "VARCHAR",
  37 + "columnComment" : "名字",
  38 + "javaType" : "String",
  39 + "javaField" : "name",
  40 + "example" : "芋头",
  41 + "createOperation" : true,
  42 + "updateOperation" : true,
  43 + "listOperation" : true,
  44 + "listOperationCondition" : "LIKE",
  45 + "listOperationResult" : true,
  46 + "htmlType" : "input"
  47 + }, {
  48 + "columnName" : "description",
  49 + "dataType" : "VARCHAR",
  50 + "columnComment" : "简介",
  51 + "javaType" : "String",
  52 + "javaField" : "description",
  53 + "example" : "我是介绍",
  54 + "createOperation" : true,
  55 + "updateOperation" : true,
  56 + "listOperationResult" : true,
  57 + "htmlType" : "textarea"
  58 + }, {
  59 + "columnName" : "birthday",
  60 + "dataType" : "DATE",
  61 + "columnComment" : "出生日期",
  62 + "javaType" : "LocalDateTime",
  63 + "javaField" : "birthday",
  64 + "createOperation" : true,
  65 + "updateOperation" : true,
  66 + "listOperation" : true,
  67 + "listOperationCondition" : "=",
  68 + "listOperationResult" : true,
  69 + "htmlType" : "datetime"
  70 + }, {
  71 + "columnName" : "sex",
  72 + "dataType" : "INTEGER",
  73 + "columnComment" : "性别",
  74 + "javaType" : "Integer",
  75 + "javaField" : "sex",
  76 + "dictType" : "system_user_sex",
  77 + "example" : "1",
  78 + "createOperation" : true,
  79 + "updateOperation" : true,
  80 + "listOperation" : true,
  81 + "listOperationCondition" : "=",
  82 + "listOperationResult" : true,
  83 + "htmlType" : "select"
  84 + }, {
  85 + "columnName" : "enabled",
  86 + "dataType" : "BOOLEAN",
  87 + "columnComment" : "是否有效",
  88 + "javaType" : "Boolean",
  89 + "javaField" : "enabled",
  90 + "dictType" : "infra_boolean_string",
  91 + "example" : "true",
  92 + "createOperation" : true,
  93 + "updateOperation" : true,
  94 + "listOperation" : true,
  95 + "listOperationCondition" : "=",
  96 + "listOperationResult" : true,
  97 + "htmlType" : "radio"
  98 + }, {
  99 + "columnName" : "avatar",
  100 + "dataType" : "VARCHAR",
  101 + "columnComment" : "头像",
  102 + "javaType" : "String",
  103 + "javaField" : "avatar",
  104 + "example" : "https://www.iocoder.cn/1.png",
  105 + "createOperation" : true,
  106 + "updateOperation" : true,
  107 + "listOperationResult" : true,
  108 + "htmlType" : "imageUpload"
  109 + }, {
  110 + "columnName" : "video",
  111 + "dataType" : "VARCHAR",
  112 + "columnComment" : "附件",
  113 + "nullable" : true,
  114 + "javaType" : "String",
  115 + "javaField" : "video",
  116 + "example" : "https://www.iocoder.cn/1.mp4",
  117 + "createOperation" : true,
  118 + "updateOperation" : true,
  119 + "listOperationResult" : true,
  120 + "htmlType" : "fileUpload"
  121 + }, {
  122 + "columnName" : "memo",
  123 + "dataType" : "VARCHAR",
  124 + "columnComment" : "备注",
  125 + "javaType" : "String",
  126 + "javaField" : "memo",
  127 + "example" : "我是备注",
  128 + "createOperation" : true,
  129 + "updateOperation" : true,
  130 + "listOperationResult" : true,
  131 + "htmlType" : "editor"
  132 + }, {
  133 + "columnName" : "create_time",
  134 + "dataType" : "DATE",
  135 + "columnComment" : "创建时间",
  136 + "nullable" : true,
  137 + "javaType" : "LocalDateTime",
  138 + "javaField" : "createTime",
  139 + "listOperation" : true,
  140 + "listOperationCondition" : "BETWEEN",
  141 + "listOperationResult" : true,
  142 + "htmlType" : "datetime"
  143 + } ]
  144 +}
0 145 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentController",
  12 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentDO",
  15 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentContactDO",
  18 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentTeacherDO",
  21 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentMapper",
  24 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  25 +}, {
  26 + "contentPath" : "java/InfraStudentContactMapper",
  27 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentTeacherMapper",
  30 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java"
  31 +}, {
  32 + "contentPath" : "xml/InfraStudentMapper",
  33 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImpl",
  36 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  37 +}, {
  38 + "contentPath" : "java/InfraStudentService",
  39 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  40 +}, {
  41 + "contentPath" : "java/InfraStudentServiceImplTest",
  42 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  43 +}, {
  44 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  45 + "filePath" : "yudao-module-infra/yudao-module-infra-api/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-vue3/src/views/infra/demo/index.vue"
  55 +}, {
  56 + "contentPath" : "vue/StudentForm",
  57 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/StudentForm.vue"
  58 +}, {
  59 + "contentPath" : "vue/StudentContactForm",
  60 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactForm.vue"
  61 +}, {
  62 + "contentPath" : "vue/StudentTeacherForm",
  63 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherForm.vue"
  64 +}, {
  65 + "contentPath" : "vue/StudentContactList",
  66 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactList.vue"
  67 +}, {
  68 + "contentPath" : "vue/StudentTeacherList",
  69 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherList.vue"
  70 +}, {
  71 + "contentPath" : "ts/index",
  72 + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts"
  73 +} ]
0 74 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/ErrorCodeConstants_手动操作 0 → 100644
  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 补充编号, "学生班主任已存在");
0 7 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentContactDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生联系人 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student_contact")
  16 +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentContactDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 学生编号
  32 + */
  33 + private Long studentId;
  34 + /**
  35 + * 名字
  36 + */
  37 + private String name;
  38 + /**
  39 + * 简介
  40 + */
  41 + private String description;
  42 + /**
  43 + * 出生日期
  44 + */
  45 + private LocalDateTime birthday;
  46 + /**
  47 + * 性别
  48 + *
  49 + * 枚举 {@link TODO system_user_sex 对应的类}
  50 + */
  51 + private Integer sex;
  52 + /**
  53 + * 是否有效
  54 + *
  55 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  56 + */
  57 + private Boolean enabled;
  58 + /**
  59 + * 头像
  60 + */
  61 + private String avatar;
  62 + /**
  63 + * 附件
  64 + */
  65 + private String video;
  66 + /**
  67 + * 备注
  68 + */
  69 + private String memo;
  70 +
  71 +}
0 72 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentContactMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +/**
  13 + * 学生联系人 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentContactMapper extends BaseMapperX<InfraStudentContactDO> {
  19 +
  20 + default PageResult<InfraStudentContactDO> selectPage(PageParam reqVO, Long studentId) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentContactDO>()
  22 + .eq(InfraStudentContactDO::getStudentId, studentId)
  23 + .orderByDesc(InfraStudentContactDO::getId));
  24 + }
  25 +
  26 + default int deleteByStudentId(Long studentId) {
  27 + return delete(InfraStudentContactDO::getStudentId, studentId);
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.security.access.prepost.PreAuthorize;
  7 +import io.swagger.v3.oas.annotations.tags.Tag;
  8 +import io.swagger.v3.oas.annotations.Parameter;
  9 +import io.swagger.v3.oas.annotations.Operation;
  10 +
  11 +import javax.validation.constraints.*;
  12 +import javax.validation.*;
  13 +import javax.servlet.http.*;
  14 +import java.util.*;
  15 +import java.io.IOException;
  16 +
  17 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  18 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  19 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  20 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  24 +
  25 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  26 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  27 +
  28 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  29 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  30 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  31 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  32 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  33 +
  34 +@Tag(name = "管理后台 - 学生")
  35 +@RestController
  36 +@RequestMapping("/infra/student")
  37 +@Validated
  38 +public class InfraStudentController {
  39 +
  40 + @Resource
  41 + private InfraStudentService studentService;
  42 +
  43 + @PostMapping("/create")
  44 + @Operation(summary = "创建学生")
  45 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  46 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  47 + return success(studentService.createStudent(createReqVO));
  48 + }
  49 +
  50 + @PutMapping("/update")
  51 + @Operation(summary = "更新学生")
  52 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  53 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  54 + studentService.updateStudent(updateReqVO);
  55 + return success(true);
  56 + }
  57 +
  58 + @DeleteMapping("/delete")
  59 + @Operation(summary = "删除学生")
  60 + @Parameter(name = "id", description = "编号", required = true)
  61 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  62 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  63 + studentService.deleteStudent(id);
  64 + return success(true);
  65 + }
  66 +
  67 + @GetMapping("/get")
  68 + @Operation(summary = "获得学生")
  69 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  70 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  71 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  72 + InfraStudentDO student = studentService.getStudent(id);
  73 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  74 + }
  75 +
  76 + @GetMapping("/page")
  77 + @Operation(summary = "获得学生分页")
  78 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  79 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  80 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  81 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  82 + }
  83 +
  84 + @GetMapping("/export-excel")
  85 + @Operation(summary = "导出学生 Excel")
  86 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  87 + @OperateLog(type = EXPORT)
  88 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  89 + HttpServletResponse response) throws IOException {
  90 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  91 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  92 + // 导出 Excel
  93 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  94 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  95 + }
  96 +
  97 + // ==================== 子表(学生联系人) ====================
  98 +
  99 + @GetMapping("/student-contact/page")
  100 + @Operation(summary = "获得学生联系人分页")
  101 + @Parameter(name = "studentId", description = "学生编号")
  102 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  103 + public CommonResult<PageResult<InfraStudentContactDO>> getStudentContactPage(PageParam pageReqVO,
  104 + @RequestParam("studentId") Long studentId) {
  105 + return success(studentService.getStudentContactPage(pageReqVO, studentId));
  106 + }
  107 +
  108 + @PostMapping("/student-contact/create")
  109 + @Operation(summary = "创建学生联系人")
  110 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  111 + public CommonResult<Long> createStudentContact(@Valid @RequestBody InfraStudentContactDO studentContact) {
  112 + return success(studentService.createStudentContact(studentContact));
  113 + }
  114 +
  115 + @PutMapping("/student-contact/update")
  116 + @Operation(summary = "更新学生联系人")
  117 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  118 + public CommonResult<Boolean> updateStudentContact(@Valid @RequestBody InfraStudentContactDO studentContact) {
  119 + studentService.updateStudentContact(studentContact);
  120 + return success(true);
  121 + }
  122 +
  123 + @DeleteMapping("/student-contact/delete")
  124 + @Parameter(name = "id", description = "编号", required = true)
  125 + @Operation(summary = "删除学生联系人")
  126 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  127 + public CommonResult<Boolean> deleteStudentContact(@RequestParam("id") Long id) {
  128 + studentService.deleteStudentContact(id);
  129 + return success(true);
  130 + }
  131 +
  132 + @GetMapping("/student-contact/get")
  133 + @Operation(summary = "获得学生联系人")
  134 + @Parameter(name = "id", description = "编号", required = true)
  135 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  136 + public CommonResult<InfraStudentContactDO> getStudentContact(@RequestParam("id") Long id) {
  137 + return success(studentService.getStudentContact(id));
  138 + }
  139 +
  140 + // ==================== 子表(学生班主任) ====================
  141 +
  142 + @GetMapping("/student-teacher/page")
  143 + @Operation(summary = "获得学生班主任分页")
  144 + @Parameter(name = "studentId", description = "学生编号")
  145 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  146 + public CommonResult<PageResult<InfraStudentTeacherDO>> getStudentTeacherPage(PageParam pageReqVO,
  147 + @RequestParam("studentId") Long studentId) {
  148 + return success(studentService.getStudentTeacherPage(pageReqVO, studentId));
  149 + }
  150 +
  151 + @PostMapping("/student-teacher/create")
  152 + @Operation(summary = "创建学生班主任")
  153 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  154 + public CommonResult<Long> createStudentTeacher(@Valid @RequestBody InfraStudentTeacherDO studentTeacher) {
  155 + return success(studentService.createStudentTeacher(studentTeacher));
  156 + }
  157 +
  158 + @PutMapping("/student-teacher/update")
  159 + @Operation(summary = "更新学生班主任")
  160 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  161 + public CommonResult<Boolean> updateStudentTeacher(@Valid @RequestBody InfraStudentTeacherDO studentTeacher) {
  162 + studentService.updateStudentTeacher(studentTeacher);
  163 + return success(true);
  164 + }
  165 +
  166 + @DeleteMapping("/student-teacher/delete")
  167 + @Parameter(name = "id", description = "编号", required = true)
  168 + @Operation(summary = "删除学生班主任")
  169 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  170 + public CommonResult<Boolean> deleteStudentTeacher(@RequestParam("id") Long id) {
  171 + studentService.deleteStudentTeacher(id);
  172 + return success(true);
  173 + }
  174 +
  175 + @GetMapping("/student-teacher/get")
  176 + @Operation(summary = "获得学生班主任")
  177 + @Parameter(name = "id", description = "编号", required = true)
  178 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  179 + public CommonResult<InfraStudentTeacherDO> getStudentTeacher(@RequestParam("id") Long id) {
  180 + return success(studentService.getStudentTeacher(id));
  181 + }
  182 +
  183 +}
0 184 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +}
0 68 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class InfraStudentPageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "名字", example = "芋头")
  19 + private String name;
  20 +
  21 + @Schema(description = "出生日期")
  22 + private LocalDateTime birthday;
  23 +
  24 + @Schema(description = "性别", example = "1")
  25 + private Integer sex;
  26 +
  27 + @Schema(description = "是否有效", example = "true")
  28 + private Boolean enabled;
  29 +
  30 + @Schema(description = "创建时间")
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + private LocalDateTime[] createTime;
  33 +
  34 +}
0 35 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import java.util.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +import com.alibaba.excel.annotation.*;
  10 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  11 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  12 +
  13 +@Schema(description = "管理后台 - 学生 Response VO")
  14 +@Data
  15 +@ExcelIgnoreUnannotated
  16 +public class InfraStudentRespVO {
  17 +
  18 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  19 + @ExcelProperty("编号")
  20 + private Long id;
  21 +
  22 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  23 + @ExcelProperty("名字")
  24 + private String name;
  25 +
  26 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  27 + @ExcelProperty("简介")
  28 + private String description;
  29 +
  30 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + @ExcelProperty("出生日期")
  32 + private LocalDateTime birthday;
  33 +
  34 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  35 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  36 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  37 + private Integer sex;
  38 +
  39 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  40 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  41 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  42 + private Boolean enabled;
  43 +
  44 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  45 + @ExcelProperty("头像")
  46 + private String avatar;
  47 +
  48 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  49 + @ExcelProperty("附件")
  50 + private String video;
  51 +
  52 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  53 + @ExcelProperty("备注")
  54 + private String memo;
  55 +
  56 + @Schema(description = "创建时间")
  57 + @ExcelProperty("创建时间")
  58 + private LocalDateTime createTime;
  59 +
  60 +}
0 61 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import javax.validation.constraints.*;
  7 +import java.util.*;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +import java.time.LocalDateTime;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  12 +
  13 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  14 +@Data
  15 +public class InfraStudentSaveReqVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + private Long id;
  19 +
  20 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  21 + @NotEmpty(message = "名字不能为空")
  22 + private String name;
  23 +
  24 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  25 + @NotEmpty(message = "简介不能为空")
  26 + private String description;
  27 +
  28 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  29 + @NotNull(message = "出生日期不能为空")
  30 + private LocalDateTime birthday;
  31 +
  32 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  33 + @NotNull(message = "性别不能为空")
  34 + private Integer sex;
  35 +
  36 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  37 + @NotNull(message = "是否有效不能为空")
  38 + private Boolean enabled;
  39 +
  40 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  41 + @NotEmpty(message = "头像不能为空")
  42 + private String avatar;
  43 +
  44 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  45 + @NotEmpty(message = "附件不能为空")
  46 + private String video;
  47 +
  48 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  49 + @NotEmpty(message = "备注不能为空")
  50 + private String memo;
  51 +
  52 +}
0 53 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import javax.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  9 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  10 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  11 +
  12 +/**
  13 + * 学生 Service 接口
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public interface InfraStudentService {
  18 +
  19 + /**
  20 + * 创建学生
  21 + *
  22 + * @param createReqVO 创建信息
  23 + * @return 编号
  24 + */
  25 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
  26 +
  27 + /**
  28 + * 更新学生
  29 + *
  30 + * @param updateReqVO 更新信息
  31 + */
  32 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
  33 +
  34 + /**
  35 + * 删除学生
  36 + *
  37 + * @param id 编号
  38 + */
  39 + void deleteStudent(Long id);
  40 +
  41 + /**
  42 + * 获得学生
  43 + *
  44 + * @param id 编号
  45 + * @return 学生
  46 + */
  47 + InfraStudentDO getStudent(Long id);
  48 +
  49 + /**
  50 + * 获得学生分页
  51 + *
  52 + * @param pageReqVO 分页查询
  53 + * @return 学生分页
  54 + */
  55 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  56 +
  57 + // ==================== 子表(学生联系人) ====================
  58 +
  59 + /**
  60 + * 获得学生联系人分页
  61 + *
  62 + * @param pageReqVO 分页查询
  63 + * @param studentId 学生编号
  64 + * @return 学生联系人分页
  65 + */
  66 + PageResult<InfraStudentContactDO> getStudentContactPage(PageParam pageReqVO, Long studentId);
  67 +
  68 + /**
  69 + * 创建学生联系人
  70 + *
  71 + * @param studentContact 创建信息
  72 + * @return 编号
  73 + */
  74 + Long createStudentContact(@Valid InfraStudentContactDO studentContact);
  75 +
  76 + /**
  77 + * 更新学生联系人
  78 + *
  79 + * @param studentContact 更新信息
  80 + */
  81 + void updateStudentContact(@Valid InfraStudentContactDO studentContact);
  82 +
  83 + /**
  84 + * 删除学生联系人
  85 + *
  86 + * @param id 编号
  87 + */
  88 + void deleteStudentContact(Long id);
  89 +
  90 + /**
  91 + * 获得学生联系人
  92 + *
  93 + * @param id 编号
  94 + * @return 学生联系人
  95 + */
  96 + InfraStudentContactDO getStudentContact(Long id);
  97 +
  98 + // ==================== 子表(学生班主任) ====================
  99 +
  100 + /**
  101 + * 获得学生班主任分页
  102 + *
  103 + * @param pageReqVO 分页查询
  104 + * @param studentId 学生编号
  105 + * @return 学生班主任分页
  106 + */
  107 + PageResult<InfraStudentTeacherDO> getStudentTeacherPage(PageParam pageReqVO, Long studentId);
  108 +
  109 + /**
  110 + * 创建学生班主任
  111 + *
  112 + * @param studentTeacher 创建信息
  113 + * @return 编号
  114 + */
  115 + Long createStudentTeacher(@Valid InfraStudentTeacherDO studentTeacher);
  116 +
  117 + /**
  118 + * 更新学生班主任
  119 + *
  120 + * @param studentTeacher 更新信息
  121 + */
  122 + void updateStudentTeacher(@Valid InfraStudentTeacherDO studentTeacher);
  123 +
  124 + /**
  125 + * 删除学生班主任
  126 + *
  127 + * @param id 编号
  128 + */
  129 + void deleteStudentTeacher(Long id);
  130 +
  131 + /**
  132 + * 获得学生班主任
  133 + *
  134 + * @param id 编号
  135 + * @return 学生班主任
  136 + */
  137 + InfraStudentTeacherDO getStudentTeacher(Long id);
  138 +
  139 +}
0 140 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.transaction.annotation.Transactional;
  7 +
  8 +import java.util.*;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  15 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  16 +
  17 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  18 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper;
  19 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class InfraStudentServiceImpl implements InfraStudentService {
  32 +
  33 + @Resource
  34 + private InfraStudentMapper studentMapper;
  35 + @Resource
  36 + private InfraStudentContactMapper studentContactMapper;
  37 + @Resource
  38 + private InfraStudentTeacherMapper studentTeacherMapper;
  39 +
  40 + @Override
  41 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  42 + // 插入
  43 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  44 + studentMapper.insert(student);
  45 + // 返回
  46 + return student.getId();
  47 + }
  48 +
  49 + @Override
  50 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  51 + // 校验存在
  52 + validateStudentExists(updateReqVO.getId());
  53 + // 更新
  54 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  55 + studentMapper.updateById(updateObj);
  56 + }
  57 +
  58 + @Override
  59 + @Transactional(rollbackFor = Exception.class)
  60 + public void deleteStudent(Long id) {
  61 + // 校验存在
  62 + validateStudentExists(id);
  63 + // 删除
  64 + studentMapper.deleteById(id);
  65 +
  66 + // 删除子表
  67 + deleteStudentContactByStudentId(id);
  68 + deleteStudentTeacherByStudentId(id);
  69 + }
  70 +
  71 + private void validateStudentExists(Long id) {
  72 + if (studentMapper.selectById(id) == null) {
  73 + throw exception(STUDENT_NOT_EXISTS);
  74 + }
  75 + }
  76 +
  77 + @Override
  78 + public InfraStudentDO getStudent(Long id) {
  79 + return studentMapper.selectById(id);
  80 + }
  81 +
  82 + @Override
  83 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  84 + return studentMapper.selectPage(pageReqVO);
  85 + }
  86 +
  87 + // ==================== 子表(学生联系人) ====================
  88 +
  89 + @Override
  90 + public PageResult<InfraStudentContactDO> getStudentContactPage(PageParam pageReqVO, Long studentId) {
  91 + return studentContactMapper.selectPage(pageReqVO, studentId);
  92 + }
  93 +
  94 + @Override
  95 + public Long createStudentContact(InfraStudentContactDO studentContact) {
  96 + studentContactMapper.insert(studentContact);
  97 + return studentContact.getId();
  98 + }
  99 +
  100 + @Override
  101 + public void updateStudentContact(InfraStudentContactDO studentContact) {
  102 + // 校验存在
  103 + validateStudentContactExists(studentContact.getId());
  104 + // 更新
  105 + studentContactMapper.updateById(studentContact);
  106 + }
  107 +
  108 + @Override
  109 + public void deleteStudentContact(Long id) {
  110 + // 校验存在
  111 + validateStudentContactExists(id);
  112 + // 删除
  113 + studentContactMapper.deleteById(id);
  114 + }
  115 +
  116 + @Override
  117 + public InfraStudentContactDO getStudentContact(Long id) {
  118 + return studentContactMapper.selectById(id);
  119 + }
  120 +
  121 + private void validateStudentContactExists(Long id) {
  122 + if (studentContactMapper.selectById(id) == null) {
  123 + throw exception(STUDENT_CONTACT_NOT_EXISTS);
  124 + }
  125 + }
  126 +
  127 + private void deleteStudentContactByStudentId(Long studentId) {
  128 + studentContactMapper.deleteByStudentId(studentId);
  129 + }
  130 +
  131 + // ==================== 子表(学生班主任) ====================
  132 +
  133 + @Override
  134 + public PageResult<InfraStudentTeacherDO> getStudentTeacherPage(PageParam pageReqVO, Long studentId) {
  135 + return studentTeacherMapper.selectPage(pageReqVO, studentId);
  136 + }
  137 +
  138 + @Override
  139 + public Long createStudentTeacher(InfraStudentTeacherDO studentTeacher) {
  140 + // 校验是否已经存在
  141 + if (studentTeacherMapper.selectByStudentId(studentTeacher.getStudentId()) != null) {
  142 + throw exception(STUDENT_TEACHER_EXISTS);
  143 + }
  144 + // 插入
  145 + studentTeacherMapper.insert(studentTeacher);
  146 + return studentTeacher.getId();
  147 + }
  148 +
  149 + @Override
  150 + public void updateStudentTeacher(InfraStudentTeacherDO studentTeacher) {
  151 + // 校验存在
  152 + validateStudentTeacherExists(studentTeacher.getId());
  153 + // 更新
  154 + studentTeacherMapper.updateById(studentTeacher);
  155 + }
  156 +
  157 + @Override
  158 + public void deleteStudentTeacher(Long id) {
  159 + // 校验存在
  160 + validateStudentTeacherExists(id);
  161 + // 删除
  162 + studentTeacherMapper.deleteById(id);
  163 + }
  164 +
  165 + @Override
  166 + public InfraStudentTeacherDO getStudentTeacher(Long id) {
  167 + return studentTeacherMapper.selectById(id);
  168 + }
  169 +
  170 + private void validateStudentTeacherExists(Long id) {
  171 + if (studentTeacherMapper.selectById(id) == null) {
  172 + throw exception(STUDENT_TEACHER_NOT_EXISTS);
  173 + }
  174 + }
  175 +
  176 + private void deleteStudentTeacherByStudentId(Long studentId) {
  177 + studentTeacherMapper.deleteByStudentId(studentId);
  178 + }
  179 +
  180 +}
0 181 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.boot.test.mock.mockito.MockBean;
  6 +
  7 +import javax.annotation.Resource;
  8 +
  9 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  10 +
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  15 +
  16 +import javax.annotation.Resource;
  17 +import org.springframework.context.annotation.Import;
  18 +import java.util.*;
  19 +import java.time.LocalDateTime;
  20 +
  21 +import static cn.hutool.core.util.RandomUtil.*;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  24 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  27 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  28 +import static org.junit.jupiter.api.Assertions.*;
  29 +import static org.mockito.Mockito.*;
  30 +
  31 +/**
  32 + * {@link InfraStudentServiceImpl} 的单元测试类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Import(InfraStudentServiceImpl.class)
  37 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  38 +
  39 + @Resource
  40 + private InfraStudentServiceImpl studentService;
  41 +
  42 + @Resource
  43 + private InfraStudentMapper studentMapper;
  44 +
  45 + @Test
  46 + public void testCreateStudent_success() {
  47 + // 准备参数
  48 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  49 +
  50 + // 调用
  51 + Long studentId = studentService.createStudent(createReqVO);
  52 + // 断言
  53 + assertNotNull(studentId);
  54 + // 校验记录的属性是否正确
  55 + InfraStudentDO student = studentMapper.selectById(studentId);
  56 + assertPojoEquals(createReqVO, student, "id");
  57 + }
  58 +
  59 + @Test
  60 + public void testUpdateStudent_success() {
  61 + // mock 数据
  62 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  63 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  64 + // 准备参数
  65 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  66 + o.setId(dbStudent.getId()); // 设置更新的 ID
  67 + });
  68 +
  69 + // 调用
  70 + studentService.updateStudent(updateReqVO);
  71 + // 校验是否更新正确
  72 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  73 + assertPojoEquals(updateReqVO, student);
  74 + }
  75 +
  76 + @Test
  77 + public void testUpdateStudent_notExists() {
  78 + // 准备参数
  79 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  80 +
  81 + // 调用, 并断言异常
  82 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  83 + }
  84 +
  85 + @Test
  86 + public void testDeleteStudent_success() {
  87 + // mock 数据
  88 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  89 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  90 + // 准备参数
  91 + Long id = dbStudent.getId();
  92 +
  93 + // 调用
  94 + studentService.deleteStudent(id);
  95 + // 校验数据不存在了
  96 + assertNull(studentMapper.selectById(id));
  97 + }
  98 +
  99 + @Test
  100 + public void testDeleteStudent_notExists() {
  101 + // 准备参数
  102 + Long id = randomLongId();
  103 +
  104 + // 调用, 并断言异常
  105 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  106 + }
  107 +
  108 + @Test
  109 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  110 + public void testGetStudentPage() {
  111 + // mock 数据
  112 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  113 + o.setName(null);
  114 + o.setBirthday(null);
  115 + o.setSex(null);
  116 + o.setEnabled(null);
  117 + o.setCreateTime(null);
  118 + });
  119 + studentMapper.insert(dbStudent);
  120 + // 测试 name 不匹配
  121 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  122 + // 测试 birthday 不匹配
  123 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  124 + // 测试 sex 不匹配
  125 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  126 + // 测试 enabled 不匹配
  127 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  128 + // 测试 createTime 不匹配
  129 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  130 + // 准备参数
  131 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  132 + reqVO.setName(null);
  133 + reqVO.setBirthday(null);
  134 + reqVO.setSex(null);
  135 + reqVO.setEnabled(null);
  136 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  137 +
  138 + // 调用
  139 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  140 + // 断言
  141 + assertEquals(1, pageResult.getTotal());
  142 + assertEquals(1, pageResult.getList().size());
  143 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  144 + }
  145 +
  146 +}
0 147 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentTeacherDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生班主任 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student_teacher")
  16 +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentTeacherDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 学生编号
  32 + */
  33 + private Long studentId;
  34 + /**
  35 + * 名字
  36 + */
  37 + private String name;
  38 + /**
  39 + * 简介
  40 + */
  41 + private String description;
  42 + /**
  43 + * 出生日期
  44 + */
  45 + private LocalDateTime birthday;
  46 + /**
  47 + * 性别
  48 + *
  49 + * 枚举 {@link TODO system_user_sex 对应的类}
  50 + */
  51 + private Integer sex;
  52 + /**
  53 + * 是否有效
  54 + *
  55 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  56 + */
  57 + private Boolean enabled;
  58 + /**
  59 + * 头像
  60 + */
  61 + private String avatar;
  62 + /**
  63 + * 附件
  64 + */
  65 + private String video;
  66 + /**
  67 + * 备注
  68 + */
  69 + private String memo;
  70 +
  71 +}
0 72 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/java/InfraStudentTeacherMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +/**
  13 + * 学生班主任 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentTeacherMapper extends BaseMapperX<InfraStudentTeacherDO> {
  19 +
  20 + default PageResult<InfraStudentTeacherDO> selectPage(PageParam reqVO, Long studentId) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentTeacherDO>()
  22 + .eq(InfraStudentTeacherDO::getStudentId, studentId)
  23 + .orderByDesc(InfraStudentTeacherDO::getId));
  24 + }
  25 +
  26 + default int deleteByStudentId(Long studentId) {
  27 + return delete(InfraStudentTeacherDO::getStudentId, studentId);
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +-- 暂时只支持 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 +);
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/ts/index 0 → 100644
  1 +import request from '@/config/axios'
  2 +
  3 +export interface StudentVO {
  4 + id: number
  5 + name: string
  6 + description: string
  7 + birthday: Date
  8 + sex: number
  9 + enabled: boolean
  10 + avatar: string
  11 + video: string
  12 + memo: string
  13 +}
  14 +
  15 +// 查询学生分页
  16 +export const getStudentPage = async (params) => {
  17 + return await request.get({ url: `/infra/student/page`, params })
  18 +}
  19 +
  20 +// 查询学生详情
  21 +export const getStudent = async (id: number) => {
  22 + return await request.get({ url: `/infra/student/get?id=` + id })
  23 +}
  24 +
  25 +// 新增学生
  26 +export const createStudent = async (data: StudentVO) => {
  27 + return await request.post({ url: `/infra/student/create`, data })
  28 +}
  29 +
  30 +// 修改学生
  31 +export const updateStudent = async (data: StudentVO) => {
  32 + return await request.put({ url: `/infra/student/update`, data })
  33 +}
  34 +
  35 +// 删除学生
  36 +export const deleteStudent = async (id: number) => {
  37 + return await request.delete({ url: `/infra/student/delete?id=` + id })
  38 +}
  39 +
  40 +// 导出学生 Excel
  41 +export const exportStudent = async (params) => {
  42 + return await request.download({ url: `/infra/student/export-excel`, params })
  43 +}
  44 +
  45 +// ==================== 子表(学生联系人) ====================
  46 +
  47 +// 获得学生联系人分页
  48 +export const getStudentContactPage = async (params) => {
  49 + return await request.get({ url: `/infra/student/student-contact/page`, params })
  50 +}
  51 +// 新增学生联系人
  52 +export const createStudentContact = async (data) => {
  53 + return await request.post({ url: `/infra/student/student-contact/create`, data })
  54 +}
  55 +
  56 +// 修改学生联系人
  57 +export const updateStudentContact = async (data) => {
  58 + return await request.put({ url: `/infra/student/student-contact/update`, data })
  59 +}
  60 +
  61 +// 删除学生联系人
  62 +export const deleteStudentContact = async (id: number) => {
  63 + return await request.delete({ url: `/infra/student/student-contact/delete?id=` + id })
  64 +}
  65 +
  66 +// 获得学生联系人
  67 +export const getStudentContact = async (id: number) => {
  68 + return await request.get({ url: `/infra/student/student-contact/get?id=` + id })
  69 +}
  70 +
  71 +// ==================== 子表(学生班主任) ====================
  72 +
  73 +// 获得学生班主任分页
  74 +export const getStudentTeacherPage = async (params) => {
  75 + return await request.get({ url: `/infra/student/student-teacher/page`, params })
  76 +}
  77 +// 新增学生班主任
  78 +export const createStudentTeacher = async (data) => {
  79 + return await request.post({ url: `/infra/student/student-teacher/create`, data })
  80 +}
  81 +
  82 +// 修改学生班主任
  83 +export const updateStudentTeacher = async (data) => {
  84 + return await request.put({ url: `/infra/student/student-teacher/update`, data })
  85 +}
  86 +
  87 +// 删除学生班主任
  88 +export const deleteStudentTeacher = async (id: number) => {
  89 + return await request.delete({ url: `/infra/student/student-teacher/delete?id=` + id })
  90 +}
  91 +
  92 +// 获得学生班主任
  93 +export const getStudentTeacher = async (id: number) => {
  94 + return await request.get({ url: `/infra/student/student-teacher/get?id=` + id })
  95 +}
0 96 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/StudentContactForm 0 → 100644
  1 +<template>
  2 + <Dialog :title="dialogTitle" v-model="dialogVisible">
  3 + <el-form
  4 + ref="formRef"
  5 + :model="formData"
  6 + :rules="formRules"
  7 + label-width="100px"
  8 + v-loading="formLoading"
  9 + >
  10 + <el-form-item label="名字" prop="name">
  11 + <el-input v-model="formData.name" placeholder="请输入名字" />
  12 + </el-form-item>
  13 + <el-form-item label="简介" prop="description">
  14 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  15 + </el-form-item>
  16 + <el-form-item label="出生日期" prop="birthday">
  17 + <el-date-picker
  18 + v-model="formData.birthday"
  19 + type="date"
  20 + value-format="x"
  21 + placeholder="选择出生日期"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item label="性别" prop="sex">
  25 + <el-select v-model="formData.sex" placeholder="请选择性别">
  26 + <el-option
  27 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  28 + :key="dict.value"
  29 + :label="dict.label"
  30 + :value="dict.value"
  31 + />
  32 + </el-select>
  33 + </el-form-item>
  34 + <el-form-item label="是否有效" prop="enabled">
  35 + <el-radio-group v-model="formData.enabled">
  36 + <el-radio
  37 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  38 + :key="dict.value"
  39 + :label="dict.value"
  40 + >
  41 + {{ dict.label }}
  42 + </el-radio>
  43 + </el-radio-group>
  44 + </el-form-item>
  45 + <el-form-item label="头像" prop="avatar">
  46 + <UploadImg v-model="formData.avatar" />
  47 + </el-form-item>
  48 + <el-form-item label="附件" prop="video">
  49 + <UploadFile v-model="formData.video" />
  50 + </el-form-item>
  51 + <el-form-item label="备注" prop="memo">
  52 + <Editor v-model="formData.memo" height="150px" />
  53 + </el-form-item>
  54 + </el-form>
  55 + <template #footer>
  56 + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  57 + <el-button @click="dialogVisible = false">取 消</el-button>
  58 + </template>
  59 + </Dialog>
  60 +</template>
  61 +<script setup lang="ts">
  62 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  63 +import * as StudentApi from '@/api/infra/demo'
  64 +
  65 +const { t } = useI18n() // 国际化
  66 +const message = useMessage() // 消息弹窗
  67 +
  68 +const dialogVisible = ref(false) // 弹窗的是否展示
  69 +const dialogTitle = ref('') // 弹窗的标题
  70 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  71 +const formType = ref('') // 表单的类型:create - 新增;update - 修改
  72 +const formData = ref({
  73 + id: undefined,
  74 + studentId: undefined,
  75 + name: undefined,
  76 + description: undefined,
  77 + birthday: undefined,
  78 + sex: undefined,
  79 + enabled: undefined,
  80 + avatar: undefined,
  81 + video: undefined,
  82 + memo: undefined
  83 +})
  84 +const formRules = reactive({
  85 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  86 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  87 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  88 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  89 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  90 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  91 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  92 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  93 +})
  94 +const formRef = ref() // 表单 Ref
  95 +
  96 +/** 打开弹窗 */
  97 +const open = async (type: string, id?: number, studentId: number) => {
  98 + dialogVisible.value = true
  99 + dialogTitle.value = t('action.' + type)
  100 + formType.value = type
  101 + resetForm()
  102 + formData.value.studentId = studentId
  103 + // 修改时,设置数据
  104 + if (id) {
  105 + formLoading.value = true
  106 + try {
  107 + formData.value = await StudentApi.getStudentContact(id)
  108 + } finally {
  109 + formLoading.value = false
  110 + }
  111 + }
  112 +}
  113 +defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  114 +
  115 +/** 提交表单 */
  116 +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  117 +const submitForm = async () => {
  118 + // 校验表单
  119 + await formRef.value.validate()
  120 + // 提交请求
  121 + formLoading.value = true
  122 + try {
  123 + const data = formData.value
  124 + if (formType.value === 'create') {
  125 + await StudentApi.createStudentContact(data)
  126 + message.success(t('common.createSuccess'))
  127 + } else {
  128 + await StudentApi.updateStudentContact(data)
  129 + message.success(t('common.updateSuccess'))
  130 + }
  131 + dialogVisible.value = false
  132 + // 发送操作成功的事件
  133 + emit('success')
  134 + } finally {
  135 + formLoading.value = false
  136 + }
  137 +}
  138 +
  139 +/** 重置表单 */
  140 +const resetForm = () => {
  141 + formData.value = {
  142 + id: undefined,
  143 + studentId: undefined,
  144 + name: undefined,
  145 + description: undefined,
  146 + birthday: undefined,
  147 + sex: undefined,
  148 + enabled: undefined,
  149 + avatar: undefined,
  150 + video: undefined,
  151 + memo: undefined
  152 + }
  153 + formRef.value?.resetFields()
  154 +}
  155 +</script>
0 156 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/StudentContactList 0 → 100644
  1 +<template>
  2 + <!-- 列表 -->
  3 + <ContentWrap>
  4 + <el-button
  5 + type="primary"
  6 + plain
  7 + @click="openForm('create')"
  8 + v-hasPermi="['infra:student:create']"
  9 + >
  10 + <Icon icon="ep:plus" class="mr-5px" /> 新增
  11 + </el-button>
  12 + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  13 + <el-table-column label="编号" align="center" prop="id" />
  14 + <el-table-column label="名字" align="center" prop="name" />
  15 + <el-table-column label="简介" align="center" prop="description" />
  16 + <el-table-column
  17 + label="出生日期"
  18 + align="center"
  19 + prop="birthday"
  20 + :formatter="dateFormatter"
  21 + width="180px"
  22 + />
  23 + <el-table-column label="性别" align="center" prop="sex">
  24 + <template #default="scope">
  25 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column label="是否有效" align="center" prop="enabled">
  29 + <template #default="scope">
  30 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  31 + </template>
  32 + </el-table-column>
  33 + <el-table-column label="头像" align="center" prop="avatar" />
  34 + <el-table-column label="附件" align="center" prop="video" />
  35 + <el-table-column label="备注" align="center" prop="memo" />
  36 + <el-table-column
  37 + label="创建时间"
  38 + align="center"
  39 + prop="createTime"
  40 + :formatter="dateFormatter"
  41 + width="180px"
  42 + />
  43 + <el-table-column label="操作" align="center">
  44 + <template #default="scope">
  45 + <el-button
  46 + link
  47 + type="primary"
  48 + @click="openForm('update', scope.row.id)"
  49 + v-hasPermi="['infra:student:update']"
  50 + >
  51 + 编辑
  52 + </el-button>
  53 + <el-button
  54 + link
  55 + type="danger"
  56 + @click="handleDelete(scope.row.id)"
  57 + v-hasPermi="['infra:student:delete']"
  58 + >
  59 + 删除
  60 + </el-button>
  61 + </template>
  62 + </el-table-column>
  63 + </el-table>
  64 + <!-- 分页 -->
  65 + <Pagination
  66 + :total="total"
  67 + v-model:page="queryParams.pageNo"
  68 + v-model:limit="queryParams.pageSize"
  69 + @pagination="getList"
  70 + />
  71 + </ContentWrap>
  72 + <!-- 表单弹窗:添加/修改 -->
  73 + <StudentContactForm ref="formRef" @success="getList" />
  74 +</template>
  75 +<script setup lang="ts">
  76 +import { DICT_TYPE } from '@/utils/dict'
  77 +import { dateFormatter } from '@/utils/formatTime'
  78 +import * as StudentApi from '@/api/infra/demo'
  79 +import StudentContactForm from './StudentContactForm.vue'
  80 +
  81 +const { t } = useI18n() // 国际化
  82 +const message = useMessage() // 消息弹窗
  83 +
  84 +const props = defineProps<{
  85 + studentId: undefined // 学生编号(主表的关联字段)
  86 +}>()
  87 +const loading = ref(false) // 列表的加载中
  88 +const list = ref([]) // 列表的数据
  89 +const total = ref(0) // 列表的总页数
  90 +const queryParams = reactive({
  91 + pageNo: 1,
  92 + pageSize: 10,
  93 + studentId: undefined
  94 +})
  95 +
  96 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  97 +watch(
  98 + () => props.studentId,
  99 + (val) => {
  100 + queryParams.studentId = val
  101 + handleQuery()
  102 + },
  103 + { immediate: false }
  104 +)
  105 +
  106 +/** 查询列表 */
  107 +const getList = async () => {
  108 + loading.value = true
  109 + try {
  110 + const data = await StudentApi.getStudentContactPage(queryParams)
  111 + list.value = data.list
  112 + total.value = data.total
  113 + } finally {
  114 + loading.value = false
  115 + }
  116 +}
  117 +
  118 +/** 搜索按钮操作 */
  119 +const handleQuery = () => {
  120 + queryParams.pageNo = 1
  121 + getList()
  122 +}
  123 +
  124 +/** 添加/修改操作 */
  125 +const formRef = ref()
  126 +const openForm = (type: string, id?: number) => {
  127 + if (!props.studentId) {
  128 + message.error('请选择一个学生')
  129 + return
  130 + }
  131 + formRef.value.open(type, id, props.studentId)
  132 +}
  133 +
  134 +/** 删除按钮操作 */
  135 +const handleDelete = async (id: number) => {
  136 + try {
  137 + // 删除的二次确认
  138 + await message.delConfirm()
  139 + // 发起删除
  140 + await StudentApi.deleteStudentContact(id)
  141 + message.success(t('common.delSuccess'))
  142 + // 刷新列表
  143 + await getList()
  144 + } catch {}
  145 +}
  146 +</script>
0 147 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/StudentForm 0 → 100644
  1 +<template>
  2 + <Dialog :title="dialogTitle" v-model="dialogVisible">
  3 + <el-form
  4 + ref="formRef"
  5 + :model="formData"
  6 + :rules="formRules"
  7 + label-width="100px"
  8 + v-loading="formLoading"
  9 + >
  10 + <el-form-item label="名字" prop="name">
  11 + <el-input v-model="formData.name" placeholder="请输入名字" />
  12 + </el-form-item>
  13 + <el-form-item label="简介" prop="description">
  14 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  15 + </el-form-item>
  16 + <el-form-item label="出生日期" prop="birthday">
  17 + <el-date-picker
  18 + v-model="formData.birthday"
  19 + type="date"
  20 + value-format="x"
  21 + placeholder="选择出生日期"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item label="性别" prop="sex">
  25 + <el-select v-model="formData.sex" placeholder="请选择性别">
  26 + <el-option
  27 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  28 + :key="dict.value"
  29 + :label="dict.label"
  30 + :value="dict.value"
  31 + />
  32 + </el-select>
  33 + </el-form-item>
  34 + <el-form-item label="是否有效" prop="enabled">
  35 + <el-radio-group v-model="formData.enabled">
  36 + <el-radio
  37 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  38 + :key="dict.value"
  39 + :label="dict.value"
  40 + >
  41 + {{ dict.label }}
  42 + </el-radio>
  43 + </el-radio-group>
  44 + </el-form-item>
  45 + <el-form-item label="头像" prop="avatar">
  46 + <UploadImg v-model="formData.avatar" />
  47 + </el-form-item>
  48 + <el-form-item label="附件" prop="video">
  49 + <UploadFile v-model="formData.video" />
  50 + </el-form-item>
  51 + <el-form-item label="备注" prop="memo">
  52 + <Editor v-model="formData.memo" height="150px" />
  53 + </el-form-item>
  54 + </el-form>
  55 + <template #footer>
  56 + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  57 + <el-button @click="dialogVisible = false">取 消</el-button>
  58 + </template>
  59 + </Dialog>
  60 +</template>
  61 +<script setup lang="ts">
  62 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  63 +import * as StudentApi from '@/api/infra/demo'
  64 +
  65 +const { t } = useI18n() // 国际化
  66 +const message = useMessage() // 消息弹窗
  67 +
  68 +const dialogVisible = ref(false) // 弹窗的是否展示
  69 +const dialogTitle = ref('') // 弹窗的标题
  70 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  71 +const formType = ref('') // 表单的类型:create - 新增;update - 修改
  72 +const formData = ref({
  73 + id: undefined,
  74 + name: undefined,
  75 + description: undefined,
  76 + birthday: undefined,
  77 + sex: undefined,
  78 + enabled: undefined,
  79 + avatar: undefined,
  80 + video: undefined,
  81 + memo: undefined
  82 +})
  83 +const formRules = reactive({
  84 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  85 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  86 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  87 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  88 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  89 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  90 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  91 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  92 +})
  93 +const formRef = ref() // 表单 Ref
  94 +
  95 +/** 打开弹窗 */
  96 +const open = async (type: string, id?: number) => {
  97 + dialogVisible.value = true
  98 + dialogTitle.value = t('action.' + type)
  99 + formType.value = type
  100 + resetForm()
  101 + // 修改时,设置数据
  102 + if (id) {
  103 + formLoading.value = true
  104 + try {
  105 + formData.value = await StudentApi.getStudent(id)
  106 + } finally {
  107 + formLoading.value = false
  108 + }
  109 + }
  110 +}
  111 +defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  112 +
  113 +/** 提交表单 */
  114 +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  115 +const submitForm = async () => {
  116 + // 校验表单
  117 + await formRef.value.validate()
  118 + // 提交请求
  119 + formLoading.value = true
  120 + try {
  121 + const data = formData.value as unknown as StudentApi.StudentVO
  122 + if (formType.value === 'create') {
  123 + await StudentApi.createStudent(data)
  124 + message.success(t('common.createSuccess'))
  125 + } else {
  126 + await StudentApi.updateStudent(data)
  127 + message.success(t('common.updateSuccess'))
  128 + }
  129 + dialogVisible.value = false
  130 + // 发送操作成功的事件
  131 + emit('success')
  132 + } finally {
  133 + formLoading.value = false
  134 + }
  135 +}
  136 +
  137 +/** 重置表单 */
  138 +const resetForm = () => {
  139 + formData.value = {
  140 + id: undefined,
  141 + name: undefined,
  142 + description: undefined,
  143 + birthday: undefined,
  144 + sex: undefined,
  145 + enabled: undefined,
  146 + avatar: undefined,
  147 + video: undefined,
  148 + memo: undefined
  149 + }
  150 + formRef.value?.resetFields()
  151 +}
  152 +</script>
0 153 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/StudentTeacherForm 0 → 100644
  1 +<template>
  2 + <Dialog :title="dialogTitle" v-model="dialogVisible">
  3 + <el-form
  4 + ref="formRef"
  5 + :model="formData"
  6 + :rules="formRules"
  7 + label-width="100px"
  8 + v-loading="formLoading"
  9 + >
  10 + <el-form-item label="名字" prop="name">
  11 + <el-input v-model="formData.name" placeholder="请输入名字" />
  12 + </el-form-item>
  13 + <el-form-item label="简介" prop="description">
  14 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  15 + </el-form-item>
  16 + <el-form-item label="出生日期" prop="birthday">
  17 + <el-date-picker
  18 + v-model="formData.birthday"
  19 + type="date"
  20 + value-format="x"
  21 + placeholder="选择出生日期"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item label="性别" prop="sex">
  25 + <el-select v-model="formData.sex" placeholder="请选择性别">
  26 + <el-option
  27 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  28 + :key="dict.value"
  29 + :label="dict.label"
  30 + :value="dict.value"
  31 + />
  32 + </el-select>
  33 + </el-form-item>
  34 + <el-form-item label="是否有效" prop="enabled">
  35 + <el-radio-group v-model="formData.enabled">
  36 + <el-radio
  37 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  38 + :key="dict.value"
  39 + :label="dict.value"
  40 + >
  41 + {{ dict.label }}
  42 + </el-radio>
  43 + </el-radio-group>
  44 + </el-form-item>
  45 + <el-form-item label="头像" prop="avatar">
  46 + <UploadImg v-model="formData.avatar" />
  47 + </el-form-item>
  48 + <el-form-item label="附件" prop="video">
  49 + <UploadFile v-model="formData.video" />
  50 + </el-form-item>
  51 + <el-form-item label="备注" prop="memo">
  52 + <Editor v-model="formData.memo" height="150px" />
  53 + </el-form-item>
  54 + </el-form>
  55 + <template #footer>
  56 + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  57 + <el-button @click="dialogVisible = false">取 消</el-button>
  58 + </template>
  59 + </Dialog>
  60 +</template>
  61 +<script setup lang="ts">
  62 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  63 +import * as StudentApi from '@/api/infra/demo'
  64 +
  65 +const { t } = useI18n() // 国际化
  66 +const message = useMessage() // 消息弹窗
  67 +
  68 +const dialogVisible = ref(false) // 弹窗的是否展示
  69 +const dialogTitle = ref('') // 弹窗的标题
  70 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  71 +const formType = ref('') // 表单的类型:create - 新增;update - 修改
  72 +const formData = ref({
  73 + id: undefined,
  74 + studentId: undefined,
  75 + name: undefined,
  76 + description: undefined,
  77 + birthday: undefined,
  78 + sex: undefined,
  79 + enabled: undefined,
  80 + avatar: undefined,
  81 + video: undefined,
  82 + memo: undefined
  83 +})
  84 +const formRules = reactive({
  85 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  86 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  87 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  88 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  89 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  90 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  91 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  92 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  93 +})
  94 +const formRef = ref() // 表单 Ref
  95 +
  96 +/** 打开弹窗 */
  97 +const open = async (type: string, id?: number, studentId: number) => {
  98 + dialogVisible.value = true
  99 + dialogTitle.value = t('action.' + type)
  100 + formType.value = type
  101 + resetForm()
  102 + formData.value.studentId = studentId
  103 + // 修改时,设置数据
  104 + if (id) {
  105 + formLoading.value = true
  106 + try {
  107 + formData.value = await StudentApi.getStudentTeacher(id)
  108 + } finally {
  109 + formLoading.value = false
  110 + }
  111 + }
  112 +}
  113 +defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  114 +
  115 +/** 提交表单 */
  116 +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  117 +const submitForm = async () => {
  118 + // 校验表单
  119 + await formRef.value.validate()
  120 + // 提交请求
  121 + formLoading.value = true
  122 + try {
  123 + const data = formData.value
  124 + if (formType.value === 'create') {
  125 + await StudentApi.createStudentTeacher(data)
  126 + message.success(t('common.createSuccess'))
  127 + } else {
  128 + await StudentApi.updateStudentTeacher(data)
  129 + message.success(t('common.updateSuccess'))
  130 + }
  131 + dialogVisible.value = false
  132 + // 发送操作成功的事件
  133 + emit('success')
  134 + } finally {
  135 + formLoading.value = false
  136 + }
  137 +}
  138 +
  139 +/** 重置表单 */
  140 +const resetForm = () => {
  141 + formData.value = {
  142 + id: undefined,
  143 + studentId: undefined,
  144 + name: undefined,
  145 + description: undefined,
  146 + birthday: undefined,
  147 + sex: undefined,
  148 + enabled: undefined,
  149 + avatar: undefined,
  150 + video: undefined,
  151 + memo: undefined
  152 + }
  153 + formRef.value?.resetFields()
  154 +}
  155 +</script>
0 156 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/StudentTeacherList 0 → 100644
  1 +<template>
  2 + <!-- 列表 -->
  3 + <ContentWrap>
  4 + <el-button
  5 + type="primary"
  6 + plain
  7 + @click="openForm('create')"
  8 + v-hasPermi="['infra:student:create']"
  9 + >
  10 + <Icon icon="ep:plus" class="mr-5px" /> 新增
  11 + </el-button>
  12 + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  13 + <el-table-column label="编号" align="center" prop="id" />
  14 + <el-table-column label="名字" align="center" prop="name" />
  15 + <el-table-column label="简介" align="center" prop="description" />
  16 + <el-table-column
  17 + label="出生日期"
  18 + align="center"
  19 + prop="birthday"
  20 + :formatter="dateFormatter"
  21 + width="180px"
  22 + />
  23 + <el-table-column label="性别" align="center" prop="sex">
  24 + <template #default="scope">
  25 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  26 + </template>
  27 + </el-table-column>
  28 + <el-table-column label="是否有效" align="center" prop="enabled">
  29 + <template #default="scope">
  30 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  31 + </template>
  32 + </el-table-column>
  33 + <el-table-column label="头像" align="center" prop="avatar" />
  34 + <el-table-column label="附件" align="center" prop="video" />
  35 + <el-table-column label="备注" align="center" prop="memo" />
  36 + <el-table-column
  37 + label="创建时间"
  38 + align="center"
  39 + prop="createTime"
  40 + :formatter="dateFormatter"
  41 + width="180px"
  42 + />
  43 + <el-table-column label="操作" align="center">
  44 + <template #default="scope">
  45 + <el-button
  46 + link
  47 + type="primary"
  48 + @click="openForm('update', scope.row.id)"
  49 + v-hasPermi="['infra:student:update']"
  50 + >
  51 + 编辑
  52 + </el-button>
  53 + <el-button
  54 + link
  55 + type="danger"
  56 + @click="handleDelete(scope.row.id)"
  57 + v-hasPermi="['infra:student:delete']"
  58 + >
  59 + 删除
  60 + </el-button>
  61 + </template>
  62 + </el-table-column>
  63 + </el-table>
  64 + <!-- 分页 -->
  65 + <Pagination
  66 + :total="total"
  67 + v-model:page="queryParams.pageNo"
  68 + v-model:limit="queryParams.pageSize"
  69 + @pagination="getList"
  70 + />
  71 + </ContentWrap>
  72 + <!-- 表单弹窗:添加/修改 -->
  73 + <StudentTeacherForm ref="formRef" @success="getList" />
  74 +</template>
  75 +<script setup lang="ts">
  76 +import { DICT_TYPE } from '@/utils/dict'
  77 +import { dateFormatter } from '@/utils/formatTime'
  78 +import * as StudentApi from '@/api/infra/demo'
  79 +import StudentTeacherForm from './StudentTeacherForm.vue'
  80 +
  81 +const { t } = useI18n() // 国际化
  82 +const message = useMessage() // 消息弹窗
  83 +
  84 +const props = defineProps<{
  85 + studentId: undefined // 学生编号(主表的关联字段)
  86 +}>()
  87 +const loading = ref(false) // 列表的加载中
  88 +const list = ref([]) // 列表的数据
  89 +const total = ref(0) // 列表的总页数
  90 +const queryParams = reactive({
  91 + pageNo: 1,
  92 + pageSize: 10,
  93 + studentId: undefined
  94 +})
  95 +
  96 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  97 +watch(
  98 + () => props.studentId,
  99 + (val) => {
  100 + queryParams.studentId = val
  101 + handleQuery()
  102 + },
  103 + { immediate: false }
  104 +)
  105 +
  106 +/** 查询列表 */
  107 +const getList = async () => {
  108 + loading.value = true
  109 + try {
  110 + const data = await StudentApi.getStudentTeacherPage(queryParams)
  111 + list.value = data.list
  112 + total.value = data.total
  113 + } finally {
  114 + loading.value = false
  115 + }
  116 +}
  117 +
  118 +/** 搜索按钮操作 */
  119 +const handleQuery = () => {
  120 + queryParams.pageNo = 1
  121 + getList()
  122 +}
  123 +
  124 +/** 添加/修改操作 */
  125 +const formRef = ref()
  126 +const openForm = (type: string, id?: number) => {
  127 + if (!props.studentId) {
  128 + message.error('请选择一个学生')
  129 + return
  130 + }
  131 + formRef.value.open(type, id, props.studentId)
  132 +}
  133 +
  134 +/** 删除按钮操作 */
  135 +const handleDelete = async (id: number) => {
  136 + try {
  137 + // 删除的二次确认
  138 + await message.delConfirm()
  139 + // 发起删除
  140 + await StudentApi.deleteStudentTeacher(id)
  141 + message.success(t('common.delSuccess'))
  142 + // 刷新列表
  143 + await getList()
  144 + } catch {}
  145 +}
  146 +</script>
0 147 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/vue/index 0 → 100644
  1 +<template>
  2 + <ContentWrap>
  3 + <!-- 搜索工作栏 -->
  4 + <el-form
  5 + class="-mb-15px"
  6 + :model="queryParams"
  7 + ref="queryFormRef"
  8 + :inline="true"
  9 + label-width="68px"
  10 + >
  11 + <el-form-item label="名字" prop="name">
  12 + <el-input
  13 + v-model="queryParams.name"
  14 + placeholder="请输入名字"
  15 + clearable
  16 + @keyup.enter="handleQuery"
  17 + class="!w-240px"
  18 + />
  19 + </el-form-item>
  20 + <el-form-item label="出生日期" prop="birthday">
  21 + <el-date-picker
  22 + v-model="queryParams.birthday"
  23 + value-format="YYYY-MM-DD"
  24 + type="date"
  25 + placeholder="选择出生日期"
  26 + clearable
  27 + class="!w-240px"
  28 + />
  29 + </el-form-item>
  30 + <el-form-item label="性别" prop="sex">
  31 + <el-select
  32 + v-model="queryParams.sex"
  33 + placeholder="请选择性别"
  34 + clearable
  35 + class="!w-240px"
  36 + >
  37 + <el-option
  38 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  39 + :key="dict.value"
  40 + :label="dict.label"
  41 + :value="dict.value"
  42 + />
  43 + </el-select>
  44 + </el-form-item>
  45 + <el-form-item label="是否有效" prop="enabled">
  46 + <el-select
  47 + v-model="queryParams.enabled"
  48 + placeholder="请选择是否有效"
  49 + clearable
  50 + class="!w-240px"
  51 + >
  52 + <el-option
  53 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  54 + :key="dict.value"
  55 + :label="dict.label"
  56 + :value="dict.value"
  57 + />
  58 + </el-select>
  59 + </el-form-item>
  60 + <el-form-item label="创建时间" prop="createTime">
  61 + <el-date-picker
  62 + v-model="queryParams.createTime"
  63 + value-format="YYYY-MM-DD HH:mm:ss"
  64 + type="daterange"
  65 + start-placeholder="开始日期"
  66 + end-placeholder="结束日期"
  67 + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  68 + class="!w-240px"
  69 + />
  70 + </el-form-item>
  71 + <el-form-item>
  72 + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
  73 + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
  74 + <el-button
  75 + type="primary"
  76 + plain
  77 + @click="openForm('create')"
  78 + v-hasPermi="['infra:student:create']"
  79 + >
  80 + <Icon icon="ep:plus" class="mr-5px" /> 新增
  81 + </el-button>
  82 + <el-button
  83 + type="success"
  84 + plain
  85 + @click="handleExport"
  86 + :loading="exportLoading"
  87 + v-hasPermi="['infra:student:export']"
  88 + >
  89 + <Icon icon="ep:download" class="mr-5px" /> 导出
  90 + </el-button>
  91 + </el-form-item>
  92 + </el-form>
  93 + </ContentWrap>
  94 +
  95 + <!-- 列表 -->
  96 + <ContentWrap>
  97 + <el-table
  98 + v-loading="loading"
  99 + :data="list"
  100 + :stripe="true"
  101 + :show-overflow-tooltip="true"
  102 + highlight-current-row
  103 + @current-change="handleCurrentChange"
  104 + >
  105 + <el-table-column label="编号" align="center" prop="id" />
  106 + <el-table-column label="名字" align="center" prop="name" />
  107 + <el-table-column label="简介" align="center" prop="description" />
  108 + <el-table-column
  109 + label="出生日期"
  110 + align="center"
  111 + prop="birthday"
  112 + :formatter="dateFormatter"
  113 + width="180px"
  114 + />
  115 + <el-table-column label="性别" align="center" prop="sex">
  116 + <template #default="scope">
  117 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  118 + </template>
  119 + </el-table-column>
  120 + <el-table-column label="是否有效" align="center" prop="enabled">
  121 + <template #default="scope">
  122 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  123 + </template>
  124 + </el-table-column>
  125 + <el-table-column label="头像" align="center" prop="avatar" />
  126 + <el-table-column label="附件" align="center" prop="video" />
  127 + <el-table-column label="备注" align="center" prop="memo" />
  128 + <el-table-column
  129 + label="创建时间"
  130 + align="center"
  131 + prop="createTime"
  132 + :formatter="dateFormatter"
  133 + width="180px"
  134 + />
  135 + <el-table-column label="操作" align="center">
  136 + <template #default="scope">
  137 + <el-button
  138 + link
  139 + type="primary"
  140 + @click="openForm('update', scope.row.id)"
  141 + v-hasPermi="['infra:student:update']"
  142 + >
  143 + 编辑
  144 + </el-button>
  145 + <el-button
  146 + link
  147 + type="danger"
  148 + @click="handleDelete(scope.row.id)"
  149 + v-hasPermi="['infra:student:delete']"
  150 + >
  151 + 删除
  152 + </el-button>
  153 + </template>
  154 + </el-table-column>
  155 + </el-table>
  156 + <!-- 分页 -->
  157 + <Pagination
  158 + :total="total"
  159 + v-model:page="queryParams.pageNo"
  160 + v-model:limit="queryParams.pageSize"
  161 + @pagination="getList"
  162 + />
  163 + </ContentWrap>
  164 +
  165 + <!-- 表单弹窗:添加/修改 -->
  166 + <StudentForm ref="formRef" @success="getList" />
  167 + <!-- 子表的列表 -->
  168 + <ContentWrap>
  169 + <el-tabs model-value="studentContact">
  170 + <el-tab-pane label="学生联系人" name="studentContact">
  171 + <StudentContactList :student-id="currentRow.id" />
  172 + </el-tab-pane>
  173 + <el-tab-pane label="学生班主任" name="studentTeacher">
  174 + <StudentTeacherList :student-id="currentRow.id" />
  175 + </el-tab-pane>
  176 + </el-tabs>
  177 + </ContentWrap>
  178 +</template>
  179 +
  180 +<script setup lang="ts">
  181 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  182 +import { dateFormatter } from '@/utils/formatTime'
  183 +import download from '@/utils/download'
  184 +import * as StudentApi from '@/api/infra/demo'
  185 +import StudentForm from './StudentForm.vue'
  186 +import StudentContactList from './components/StudentContactList.vue'
  187 +import StudentTeacherList from './components/StudentTeacherList.vue'
  188 +
  189 +defineOptions({ name: 'InfraStudent' })
  190 +
  191 +const message = useMessage() // 消息弹窗
  192 +const { t } = useI18n() // 国际化
  193 +
  194 +const loading = ref(true) // 列表的加载中
  195 +const list = ref([]) // 列表的数据
  196 +const total = ref(0) // 列表的总页数
  197 +const queryParams = reactive({
  198 + pageNo: 1,
  199 + pageSize: 10,
  200 + name: null,
  201 + birthday: null,
  202 + birthday: [],
  203 + sex: null,
  204 + enabled: null,
  205 + createTime: []
  206 +})
  207 +const queryFormRef = ref() // 搜索的表单
  208 +const exportLoading = ref(false) // 导出的加载中
  209 +
  210 +/** 查询列表 */
  211 +const getList = async () => {
  212 + loading.value = true
  213 + try {
  214 + const data = await StudentApi.getStudentPage(queryParams)
  215 + list.value = data.list
  216 + total.value = data.total
  217 + } finally {
  218 + loading.value = false
  219 + }
  220 +}
  221 +
  222 +/** 搜索按钮操作 */
  223 +const handleQuery = () => {
  224 + queryParams.pageNo = 1
  225 + getList()
  226 +}
  227 +
  228 +/** 重置按钮操作 */
  229 +const resetQuery = () => {
  230 + queryFormRef.value.resetFields()
  231 + handleQuery()
  232 +}
  233 +
  234 +/** 添加/修改操作 */
  235 +const formRef = ref()
  236 +const openForm = (type: string, id?: number) => {
  237 + formRef.value.open(type, id)
  238 +}
  239 +
  240 +/** 删除按钮操作 */
  241 +const handleDelete = async (id: number) => {
  242 + try {
  243 + // 删除的二次确认
  244 + await message.delConfirm()
  245 + // 发起删除
  246 + await StudentApi.deleteStudent(id)
  247 + message.success(t('common.delSuccess'))
  248 + // 刷新列表
  249 + await getList()
  250 + } catch {}
  251 +}
  252 +
  253 +/** 导出按钮操作 */
  254 +const handleExport = async () => {
  255 + try {
  256 + // 导出的二次确认
  257 + await message.exportConfirm()
  258 + // 发起导出
  259 + exportLoading.value = true
  260 + const data = await StudentApi.exportStudent(queryParams)
  261 + download.excel(data, '学生.xls')
  262 + } catch {
  263 + } finally {
  264 + exportLoading.value = false
  265 + }
  266 +}
  267 +
  268 +/** 选中行操作 */
  269 +const currentRow = ref({}) // 选中行
  270 +const handleCurrentChange = (row) => {
  271 + currentRow.value = row
  272 +}
  273 +
  274 +/** 初始化 **/
  275 +onMounted(() => {
  276 + getList()
  277 +})
  278 +</script>
0 279 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/test/TestDemoMapper.xml renamed to yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_erp/xml/InfraStudentMapper
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3   -<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.test.TestDemoMapper">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
4 4  
5 5 <!--
6 6 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
... ... @@ -9,8 +9,4 @@
9 9 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
10 10 -->
11 11  
12   - <select id="selectList2" resultType="cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO">
13   - SELECT * FROM infra_test_demo
14   - </select>
15   -
16   -</mapper>
  12 +</mapper>
17 13 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentController",
  12 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentDO",
  15 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentContactDO",
  18 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentTeacherDO",
  21 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentMapper",
  24 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  25 +}, {
  26 + "contentPath" : "java/InfraStudentContactMapper",
  27 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentTeacherMapper",
  30 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java"
  31 +}, {
  32 + "contentPath" : "xml/InfraStudentMapper",
  33 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImpl",
  36 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  37 +}, {
  38 + "contentPath" : "java/InfraStudentService",
  39 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  40 +}, {
  41 + "contentPath" : "java/InfraStudentServiceImplTest",
  42 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  43 +}, {
  44 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  45 + "filePath" : "yudao-module-infra/yudao-module-infra-api/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-vue3/src/views/infra/demo/index.vue"
  55 +}, {
  56 + "contentPath" : "vue/StudentForm",
  57 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/StudentForm.vue"
  58 +}, {
  59 + "contentPath" : "vue/StudentContactForm",
  60 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactForm.vue"
  61 +}, {
  62 + "contentPath" : "vue/StudentTeacherForm",
  63 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherForm.vue"
  64 +}, {
  65 + "contentPath" : "vue/StudentContactList",
  66 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactList.vue"
  67 +}, {
  68 + "contentPath" : "vue/StudentTeacherList",
  69 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherList.vue"
  70 +}, {
  71 + "contentPath" : "ts/index",
  72 + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts"
  73 +} ]
0 74 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/ErrorCodeConstants_手动操作 0 → 100644
  1 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  2 +// ========== 学生 TODO 补充编号 ==========
  3 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
0 4 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentContactDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生联系人 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student_contact")
  16 +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentContactDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 学生编号
  32 + */
  33 + private Long studentId;
  34 + /**
  35 + * 名字
  36 + */
  37 + private String name;
  38 + /**
  39 + * 简介
  40 + */
  41 + private String description;
  42 + /**
  43 + * 出生日期
  44 + */
  45 + private LocalDateTime birthday;
  46 + /**
  47 + * 性别
  48 + *
  49 + * 枚举 {@link TODO system_user_sex 对应的类}
  50 + */
  51 + private Integer sex;
  52 + /**
  53 + * 是否有效
  54 + *
  55 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  56 + */
  57 + private Boolean enabled;
  58 + /**
  59 + * 头像
  60 + */
  61 + private String avatar;
  62 + /**
  63 + * 附件
  64 + */
  65 + private String video;
  66 + /**
  67 + * 备注
  68 + */
  69 + private String memo;
  70 +
  71 +}
0 72 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentContactMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +/**
  13 + * 学生联系人 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentContactMapper extends BaseMapperX<InfraStudentContactDO> {
  19 +
  20 + default List<InfraStudentContactDO> selectListByStudentId(Long studentId) {
  21 + return selectList(InfraStudentContactDO::getStudentId, studentId);
  22 + }
  23 +
  24 + default int deleteByStudentId(Long studentId) {
  25 + return delete(InfraStudentContactDO::getStudentId, studentId);
  26 + }
  27 +
  28 +}
0 29 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.security.access.prepost.PreAuthorize;
  7 +import io.swagger.v3.oas.annotations.tags.Tag;
  8 +import io.swagger.v3.oas.annotations.Parameter;
  9 +import io.swagger.v3.oas.annotations.Operation;
  10 +
  11 +import javax.validation.constraints.*;
  12 +import javax.validation.*;
  13 +import javax.servlet.http.*;
  14 +import java.util.*;
  15 +import java.io.IOException;
  16 +
  17 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  18 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  19 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  20 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  24 +
  25 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  26 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  27 +
  28 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  29 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  30 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  31 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  32 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  33 +
  34 +@Tag(name = "管理后台 - 学生")
  35 +@RestController
  36 +@RequestMapping("/infra/student")
  37 +@Validated
  38 +public class InfraStudentController {
  39 +
  40 + @Resource
  41 + private InfraStudentService studentService;
  42 +
  43 + @PostMapping("/create")
  44 + @Operation(summary = "创建学生")
  45 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  46 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  47 + return success(studentService.createStudent(createReqVO));
  48 + }
  49 +
  50 + @PutMapping("/update")
  51 + @Operation(summary = "更新学生")
  52 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  53 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  54 + studentService.updateStudent(updateReqVO);
  55 + return success(true);
  56 + }
  57 +
  58 + @DeleteMapping("/delete")
  59 + @Operation(summary = "删除学生")
  60 + @Parameter(name = "id", description = "编号", required = true)
  61 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  62 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  63 + studentService.deleteStudent(id);
  64 + return success(true);
  65 + }
  66 +
  67 + @GetMapping("/get")
  68 + @Operation(summary = "获得学生")
  69 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  70 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  71 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  72 + InfraStudentDO student = studentService.getStudent(id);
  73 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  74 + }
  75 +
  76 + @GetMapping("/page")
  77 + @Operation(summary = "获得学生分页")
  78 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  79 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  80 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  81 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  82 + }
  83 +
  84 + @GetMapping("/export-excel")
  85 + @Operation(summary = "导出学生 Excel")
  86 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  87 + @OperateLog(type = EXPORT)
  88 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  89 + HttpServletResponse response) throws IOException {
  90 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  91 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  92 + // 导出 Excel
  93 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  94 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  95 + }
  96 +
  97 + // ==================== 子表(学生联系人) ====================
  98 +
  99 + @GetMapping("/student-contact/list-by-student-id")
  100 + @Operation(summary = "获得学生联系人列表")
  101 + @Parameter(name = "studentId", description = "学生编号")
  102 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  103 + public CommonResult<List<InfraStudentContactDO>> getStudentContactListByStudentId(@RequestParam("studentId") Long studentId) {
  104 + return success(studentService.getStudentContactListByStudentId(studentId));
  105 + }
  106 +
  107 + // ==================== 子表(学生班主任) ====================
  108 +
  109 + @GetMapping("/student-teacher/get-by-student-id")
  110 + @Operation(summary = "获得学生班主任")
  111 + @Parameter(name = "studentId", description = "学生编号")
  112 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  113 + public CommonResult<InfraStudentTeacherDO> getStudentTeacherByStudentId(@RequestParam("studentId") Long studentId) {
  114 + return success(studentService.getStudentTeacherByStudentId(studentId));
  115 + }
  116 +
  117 +}
0 118 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +}
0 68 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class InfraStudentPageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "名字", example = "芋头")
  19 + private String name;
  20 +
  21 + @Schema(description = "出生日期")
  22 + private LocalDateTime birthday;
  23 +
  24 + @Schema(description = "性别", example = "1")
  25 + private Integer sex;
  26 +
  27 + @Schema(description = "是否有效", example = "true")
  28 + private Boolean enabled;
  29 +
  30 + @Schema(description = "创建时间")
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + private LocalDateTime[] createTime;
  33 +
  34 +}
0 35 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import java.util.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +import com.alibaba.excel.annotation.*;
  10 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  11 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  12 +
  13 +@Schema(description = "管理后台 - 学生 Response VO")
  14 +@Data
  15 +@ExcelIgnoreUnannotated
  16 +public class InfraStudentRespVO {
  17 +
  18 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  19 + @ExcelProperty("编号")
  20 + private Long id;
  21 +
  22 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  23 + @ExcelProperty("名字")
  24 + private String name;
  25 +
  26 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  27 + @ExcelProperty("简介")
  28 + private String description;
  29 +
  30 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + @ExcelProperty("出生日期")
  32 + private LocalDateTime birthday;
  33 +
  34 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  35 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  36 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  37 + private Integer sex;
  38 +
  39 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  40 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  41 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  42 + private Boolean enabled;
  43 +
  44 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  45 + @ExcelProperty("头像")
  46 + private String avatar;
  47 +
  48 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  49 + @ExcelProperty("附件")
  50 + private String video;
  51 +
  52 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  53 + @ExcelProperty("备注")
  54 + private String memo;
  55 +
  56 + @Schema(description = "创建时间")
  57 + @ExcelProperty("创建时间")
  58 + private LocalDateTime createTime;
  59 +
  60 +}
0 61 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import javax.validation.constraints.*;
  7 +import java.util.*;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +import java.time.LocalDateTime;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  12 +
  13 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  14 +@Data
  15 +public class InfraStudentSaveReqVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + private Long id;
  19 +
  20 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  21 + @NotEmpty(message = "名字不能为空")
  22 + private String name;
  23 +
  24 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  25 + @NotEmpty(message = "简介不能为空")
  26 + private String description;
  27 +
  28 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  29 + @NotNull(message = "出生日期不能为空")
  30 + private LocalDateTime birthday;
  31 +
  32 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  33 + @NotNull(message = "性别不能为空")
  34 + private Integer sex;
  35 +
  36 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  37 + @NotNull(message = "是否有效不能为空")
  38 + private Boolean enabled;
  39 +
  40 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  41 + @NotEmpty(message = "头像不能为空")
  42 + private String avatar;
  43 +
  44 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  45 + @NotEmpty(message = "附件不能为空")
  46 + private String video;
  47 +
  48 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  49 + @NotEmpty(message = "备注不能为空")
  50 + private String memo;
  51 +
  52 + @Schema(description = "学生联系人列表")
  53 + private List<InfraStudentContactDO> studentContacts;
  54 +
  55 + @Schema(description = "学生班主任")
  56 + private InfraStudentTeacherDO studentTeacher;
  57 +
  58 +}
0 59 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/test/TestDemoService.java renamed to yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentService 100755 → 100644
1   -package cn.iocoder.yudao.module.infra.service.test;
  1 +package cn.iocoder.yudao.module.infra.service.demo;
2 2  
  3 +import java.util.*;
  4 +import javax.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
3 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoCreateReqVO;
5   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoExportReqVO;
6   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoPageReqVO;
7   -import cn.iocoder.yudao.module.infra.controller.admin.test.vo.TestDemoUpdateReqVO;
8   -import cn.iocoder.yudao.module.infra.dal.dataobject.test.TestDemoDO;
9   -
10   -import javax.validation.Valid;
11   -import java.util.Collection;
12   -import java.util.List;
  10 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
13 11  
14 12 /**
15   - * 字典类型 Service 接口
  13 + * 学生 Service 接口
16 14 *
17 15 * @author 芋道源码
18 16 */
19   -public interface TestDemoService {
  17 +public interface InfraStudentService {
20 18  
21 19 /**
22   - * 创建字典类型
  20 + * 创建学生
23 21 *
24 22 * @param createReqVO 创建信息
25 23 * @return 编号
26 24 */
27   - Long createTestDemo(@Valid TestDemoCreateReqVO createReqVO);
  25 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
28 26  
29 27 /**
30   - * 更新字典类型
  28 + * 更新学生
31 29 *
32 30 * @param updateReqVO 更新信息
33 31 */
34   - void updateTestDemo(@Valid TestDemoUpdateReqVO updateReqVO);
  32 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
35 33  
36 34 /**
37   - * 删除字典类型
  35 + * 删除学生
38 36 *
39 37 * @param id 编号
40 38 */
41   - void deleteTestDemo(Long id);
  39 + void deleteStudent(Long id);
42 40  
43 41 /**
44   - * 获得字典类型
  42 + * 获得学生
45 43 *
46 44 * @param id 编号
47   - * @return 字典类型
  45 + * @return 学生
48 46 */
49   - TestDemoDO getTestDemo(Long id);
  47 + InfraStudentDO getStudent(Long id);
50 48  
51 49 /**
52   - * 获得字典类型列表
  50 + * 获得学生分页
53 51 *
54   - * @param ids 编号
55   - * @return 字典类型列表
  52 + * @param pageReqVO 分页查询
  53 + * @return 学生分页
56 54 */
57   - List<TestDemoDO> getTestDemoList(Collection<Long> ids);
  55 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  56 +
  57 + // ==================== 子表(学生联系人) ====================
58 58  
59 59 /**
60   - * 获得字典类型分页
  60 + * 获得学生联系人列表
61 61 *
62   - * @param pageReqVO 分页查询
63   - * @return 字典类型分页
  62 + * @param studentId 学生编号
  63 + * @return 学生联系人列表
64 64 */
65   - PageResult<TestDemoDO> getTestDemoPage(TestDemoPageReqVO pageReqVO);
  65 + List<InfraStudentContactDO> getStudentContactListByStudentId(Long studentId);
  66 +
  67 + // ==================== 子表(学生班主任) ====================
66 68  
67 69 /**
68   - * 获得字典类型列表, 用于 Excel 导出
  70 + * 获得学生班主任
69 71 *
70   - * @param exportReqVO 查询条件
71   - * @return 字典类型列表
  72 + * @param studentId 学生编号
  73 + * @return 学生班主任
72 74 */
73   - List<TestDemoDO> getTestDemoList(TestDemoExportReqVO exportReqVO);
  75 + InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId);
74 76  
75 77 -}
  78 +}
76 79 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.transaction.annotation.Transactional;
  7 +
  8 +import java.util.*;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  15 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  16 +
  17 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  18 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper;
  19 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class InfraStudentServiceImpl implements InfraStudentService {
  32 +
  33 + @Resource
  34 + private InfraStudentMapper studentMapper;
  35 + @Resource
  36 + private InfraStudentContactMapper studentContactMapper;
  37 + @Resource
  38 + private InfraStudentTeacherMapper studentTeacherMapper;
  39 +
  40 + @Override
  41 + @Transactional(rollbackFor = Exception.class)
  42 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  43 + // 插入
  44 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  45 + studentMapper.insert(student);
  46 +
  47 + // 插入子表
  48 + createStudentContactList(student.getId(), createReqVO.getStudentContacts());
  49 + createStudentTeacher(student.getId(), createReqVO.getStudentTeacher());
  50 + // 返回
  51 + return student.getId();
  52 + }
  53 +
  54 + @Override
  55 + @Transactional(rollbackFor = Exception.class)
  56 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  57 + // 校验存在
  58 + validateStudentExists(updateReqVO.getId());
  59 + // 更新
  60 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  61 + studentMapper.updateById(updateObj);
  62 +
  63 + // 更新子表
  64 + updateStudentContactList(updateReqVO.getId(), updateReqVO.getStudentContacts());
  65 + updateStudentTeacher(updateReqVO.getId(), updateReqVO.getStudentTeacher());
  66 + }
  67 +
  68 + @Override
  69 + @Transactional(rollbackFor = Exception.class)
  70 + public void deleteStudent(Long id) {
  71 + // 校验存在
  72 + validateStudentExists(id);
  73 + // 删除
  74 + studentMapper.deleteById(id);
  75 +
  76 + // 删除子表
  77 + deleteStudentContactByStudentId(id);
  78 + deleteStudentTeacherByStudentId(id);
  79 + }
  80 +
  81 + private void validateStudentExists(Long id) {
  82 + if (studentMapper.selectById(id) == null) {
  83 + throw exception(STUDENT_NOT_EXISTS);
  84 + }
  85 + }
  86 +
  87 + @Override
  88 + public InfraStudentDO getStudent(Long id) {
  89 + return studentMapper.selectById(id);
  90 + }
  91 +
  92 + @Override
  93 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  94 + return studentMapper.selectPage(pageReqVO);
  95 + }
  96 +
  97 + // ==================== 子表(学生联系人) ====================
  98 +
  99 + @Override
  100 + public List<InfraStudentContactDO> getStudentContactListByStudentId(Long studentId) {
  101 + return studentContactMapper.selectListByStudentId(studentId);
  102 + }
  103 +
  104 + private void createStudentContactList(Long studentId, List<InfraStudentContactDO> list) {
  105 + list.forEach(o -> o.setStudentId(studentId));
  106 + studentContactMapper.insertBatch(list);
  107 + }
  108 +
  109 + 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);
  113 + }
  114 +
  115 + private void deleteStudentContactByStudentId(Long studentId) {
  116 + studentContactMapper.deleteByStudentId(studentId);
  117 + }
  118 +
  119 + // ==================== 子表(学生班主任) ====================
  120 +
  121 + @Override
  122 + public InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId) {
  123 + return studentTeacherMapper.selectByStudentId(studentId);
  124 + }
  125 +
  126 + private void createStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) {
  127 + if (studentTeacher == null) {
  128 + return;
  129 + }
  130 + studentTeacher.setStudentId(studentId);
  131 + studentTeacherMapper.insert(studentTeacher);
  132 + }
  133 +
  134 + private void updateStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) {
  135 + if (studentTeacher == null) {
  136 + return;
  137 + }
  138 + studentTeacher.setStudentId(studentId);
  139 + studentTeacher.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新
  140 + studentTeacherMapper.insertOrUpdate(studentTeacher);
  141 + }
  142 +
  143 + private void deleteStudentTeacherByStudentId(Long studentId) {
  144 + studentTeacherMapper.deleteByStudentId(studentId);
  145 + }
  146 +
  147 +}
0 148 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.boot.test.mock.mockito.MockBean;
  6 +
  7 +import javax.annotation.Resource;
  8 +
  9 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  10 +
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  15 +
  16 +import javax.annotation.Resource;
  17 +import org.springframework.context.annotation.Import;
  18 +import java.util.*;
  19 +import java.time.LocalDateTime;
  20 +
  21 +import static cn.hutool.core.util.RandomUtil.*;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  24 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  27 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  28 +import static org.junit.jupiter.api.Assertions.*;
  29 +import static org.mockito.Mockito.*;
  30 +
  31 +/**
  32 + * {@link InfraStudentServiceImpl} 的单元测试类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Import(InfraStudentServiceImpl.class)
  37 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  38 +
  39 + @Resource
  40 + private InfraStudentServiceImpl studentService;
  41 +
  42 + @Resource
  43 + private InfraStudentMapper studentMapper;
  44 +
  45 + @Test
  46 + public void testCreateStudent_success() {
  47 + // 准备参数
  48 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  49 +
  50 + // 调用
  51 + Long studentId = studentService.createStudent(createReqVO);
  52 + // 断言
  53 + assertNotNull(studentId);
  54 + // 校验记录的属性是否正确
  55 + InfraStudentDO student = studentMapper.selectById(studentId);
  56 + assertPojoEquals(createReqVO, student, "id");
  57 + }
  58 +
  59 + @Test
  60 + public void testUpdateStudent_success() {
  61 + // mock 数据
  62 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  63 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  64 + // 准备参数
  65 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  66 + o.setId(dbStudent.getId()); // 设置更新的 ID
  67 + });
  68 +
  69 + // 调用
  70 + studentService.updateStudent(updateReqVO);
  71 + // 校验是否更新正确
  72 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  73 + assertPojoEquals(updateReqVO, student);
  74 + }
  75 +
  76 + @Test
  77 + public void testUpdateStudent_notExists() {
  78 + // 准备参数
  79 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  80 +
  81 + // 调用, 并断言异常
  82 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  83 + }
  84 +
  85 + @Test
  86 + public void testDeleteStudent_success() {
  87 + // mock 数据
  88 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  89 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  90 + // 准备参数
  91 + Long id = dbStudent.getId();
  92 +
  93 + // 调用
  94 + studentService.deleteStudent(id);
  95 + // 校验数据不存在了
  96 + assertNull(studentMapper.selectById(id));
  97 + }
  98 +
  99 + @Test
  100 + public void testDeleteStudent_notExists() {
  101 + // 准备参数
  102 + Long id = randomLongId();
  103 +
  104 + // 调用, 并断言异常
  105 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  106 + }
  107 +
  108 + @Test
  109 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  110 + public void testGetStudentPage() {
  111 + // mock 数据
  112 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  113 + o.setName(null);
  114 + o.setBirthday(null);
  115 + o.setSex(null);
  116 + o.setEnabled(null);
  117 + o.setCreateTime(null);
  118 + });
  119 + studentMapper.insert(dbStudent);
  120 + // 测试 name 不匹配
  121 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  122 + // 测试 birthday 不匹配
  123 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  124 + // 测试 sex 不匹配
  125 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  126 + // 测试 enabled 不匹配
  127 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  128 + // 测试 createTime 不匹配
  129 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  130 + // 准备参数
  131 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  132 + reqVO.setName(null);
  133 + reqVO.setBirthday(null);
  134 + reqVO.setSex(null);
  135 + reqVO.setEnabled(null);
  136 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  137 +
  138 + // 调用
  139 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  140 + // 断言
  141 + assertEquals(1, pageResult.getTotal());
  142 + assertEquals(1, pageResult.getList().size());
  143 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  144 + }
  145 +
  146 +}
0 147 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentTeacherDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生班主任 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student_teacher")
  16 +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentTeacherDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 学生编号
  32 + */
  33 + private Long studentId;
  34 + /**
  35 + * 名字
  36 + */
  37 + private String name;
  38 + /**
  39 + * 简介
  40 + */
  41 + private String description;
  42 + /**
  43 + * 出生日期
  44 + */
  45 + private LocalDateTime birthday;
  46 + /**
  47 + * 性别
  48 + *
  49 + * 枚举 {@link TODO system_user_sex 对应的类}
  50 + */
  51 + private Integer sex;
  52 + /**
  53 + * 是否有效
  54 + *
  55 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  56 + */
  57 + private Boolean enabled;
  58 + /**
  59 + * 头像
  60 + */
  61 + private String avatar;
  62 + /**
  63 + * 附件
  64 + */
  65 + private String video;
  66 + /**
  67 + * 备注
  68 + */
  69 + private String memo;
  70 +
  71 +}
0 72 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/java/InfraStudentTeacherMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +/**
  13 + * 学生班主任 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentTeacherMapper extends BaseMapperX<InfraStudentTeacherDO> {
  19 +
  20 + default InfraStudentTeacherDO selectByStudentId(Long studentId) {
  21 + return selectOne(InfraStudentTeacherDO::getStudentId, studentId);
  22 + }
  23 +
  24 + default int deleteByStudentId(Long studentId) {
  25 + return delete(InfraStudentTeacherDO::getStudentId, studentId);
  26 + }
  27 +
  28 +}
0 29 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +-- 暂时只支持 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 +);
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/ts/index 0 → 100644
  1 +import request from '@/config/axios'
  2 +
  3 +export interface StudentVO {
  4 + id: number
  5 + name: string
  6 + description: string
  7 + birthday: Date
  8 + sex: number
  9 + enabled: boolean
  10 + avatar: string
  11 + video: string
  12 + memo: string
  13 +}
  14 +
  15 +// 查询学生分页
  16 +export const getStudentPage = async (params) => {
  17 + return await request.get({ url: `/infra/student/page`, params })
  18 +}
  19 +
  20 +// 查询学生详情
  21 +export const getStudent = async (id: number) => {
  22 + return await request.get({ url: `/infra/student/get?id=` + id })
  23 +}
  24 +
  25 +// 新增学生
  26 +export const createStudent = async (data: StudentVO) => {
  27 + return await request.post({ url: `/infra/student/create`, data })
  28 +}
  29 +
  30 +// 修改学生
  31 +export const updateStudent = async (data: StudentVO) => {
  32 + return await request.put({ url: `/infra/student/update`, data })
  33 +}
  34 +
  35 +// 删除学生
  36 +export const deleteStudent = async (id: number) => {
  37 + return await request.delete({ url: `/infra/student/delete?id=` + id })
  38 +}
  39 +
  40 +// 导出学生 Excel
  41 +export const exportStudent = async (params) => {
  42 + return await request.download({ url: `/infra/student/export-excel`, params })
  43 +}
  44 +
  45 +// ==================== 子表(学生联系人) ====================
  46 +
  47 +// 获得学生联系人列表
  48 +export const getStudentContactListByStudentId = async (studentId) => {
  49 + return await request.get({ url: `/infra/student/student-contact/list-by-student-id?studentId=` + studentId })
  50 +}
  51 +
  52 +// ==================== 子表(学生班主任) ====================
  53 +
  54 +// 获得学生班主任
  55 +export const getStudentTeacherByStudentId = async (studentId) => {
  56 + return await request.get({ url: `/infra/student/student-teacher/get-by-student-id?studentId=` + studentId })
  57 +}
0 58 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/StudentContactForm 0 → 100644
  1 +<template>
  2 + <el-form
  3 + ref="formRef"
  4 + :model="formData"
  5 + :rules="formRules"
  6 + v-loading="formLoading"
  7 + label-width="0px"
  8 + :inline-message="true"
  9 + >
  10 + <el-table :data="formData" class="-mt-10px">
  11 + <el-table-column label="序号" type="index" width="100" />
  12 + <el-table-column label="名字" min-width="150">
  13 + <template #default="{ row, $index }">
  14 + <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!">
  15 + <el-input v-model="row.name" placeholder="请输入名字" />
  16 + </el-form-item>
  17 + </template>
  18 + </el-table-column>
  19 + <el-table-column label="简介" min-width="200">
  20 + <template #default="{ row, $index }">
  21 + <el-form-item :prop="`${$index}.description`" :rules="formRules.description" class="mb-0px!">
  22 + <el-input v-model="row.description" type="textarea" placeholder="请输入简介" />
  23 + </el-form-item>
  24 + </template>
  25 + </el-table-column>
  26 + <el-table-column label="出生日期" min-width="150">
  27 + <template #default="{ row, $index }">
  28 + <el-form-item :prop="`${$index}.birthday`" :rules="formRules.birthday" class="mb-0px!">
  29 + <el-date-picker
  30 + v-model="row.birthday"
  31 + type="date"
  32 + value-format="x"
  33 + placeholder="选择出生日期"
  34 + />
  35 + </el-form-item>
  36 + </template>
  37 + </el-table-column>
  38 + <el-table-column label="性别" min-width="150">
  39 + <template #default="{ row, $index }">
  40 + <el-form-item :prop="`${$index}.sex`" :rules="formRules.sex" class="mb-0px!">
  41 + <el-select v-model="row.sex" placeholder="请选择性别">
  42 + <el-option
  43 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  44 + :key="dict.value"
  45 + :label="dict.label"
  46 + :value="dict.value"
  47 + />
  48 + </el-select>
  49 + </el-form-item>
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column label="是否有效" min-width="150">
  53 + <template #default="{ row, $index }">
  54 + <el-form-item :prop="`${$index}.enabled`" :rules="formRules.enabled" class="mb-0px!">
  55 + <el-radio-group v-model="row.enabled">
  56 + <el-radio
  57 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  58 + :key="dict.value"
  59 + :label="dict.value"
  60 + >
  61 + {{ dict.label }}
  62 + </el-radio>
  63 + </el-radio-group>
  64 + </el-form-item>
  65 + </template>
  66 + </el-table-column>
  67 + <el-table-column label="头像" min-width="200">
  68 + <template #default="{ row, $index }">
  69 + <el-form-item :prop="`${$index}.avatar`" :rules="formRules.avatar" class="mb-0px!">
  70 + <UploadImg v-model="row.avatar" />
  71 + </el-form-item>
  72 + </template>
  73 + </el-table-column>
  74 + <el-table-column label="附件" min-width="200">
  75 + <template #default="{ row, $index }">
  76 + <el-form-item :prop="`${$index}.video`" :rules="formRules.video" class="mb-0px!">
  77 + <UploadFile v-model="row.video" />
  78 + </el-form-item>
  79 + </template>
  80 + </el-table-column>
  81 + <el-table-column label="备注" min-width="400">
  82 + <template #default="{ row, $index }">
  83 + <el-form-item :prop="`${$index}.memo`" :rules="formRules.memo" class="mb-0px!">
  84 + <Editor v-model="row.memo" height="150px" />
  85 + </el-form-item>
  86 + </template>
  87 + </el-table-column>
  88 + <el-table-column align="center" fixed="right" label="操作" width="60">
  89 + <template #default="{ $index }">
  90 + <el-button @click="handleDelete($index)" link>—</el-button>
  91 + </template>
  92 + </el-table-column>
  93 + </el-table>
  94 + </el-form>
  95 + <el-row justify="center" class="mt-3">
  96 + <el-button @click="handleAdd" round>+ 添加学生联系人</el-button>
  97 + </el-row>
  98 +</template>
  99 +<script setup lang="ts">
  100 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  101 +import * as StudentApi from '@/api/infra/demo'
  102 +
  103 +const props = defineProps<{
  104 + studentId: undefined // 学生编号(主表的关联字段)
  105 +}>()
  106 +const formLoading = ref(false) // 表单的加载中
  107 +const formData = ref([])
  108 +const formRules = reactive({
  109 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  110 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  111 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  112 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  113 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  114 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  115 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  116 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  117 +})
  118 +const formRef = ref() // 表单 Ref
  119 +
  120 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  121 +watch(
  122 + () => props.studentId,
  123 + async (val) => {
  124 + // 1. 重置表单
  125 + formData.value = []
  126 + // 2. val 非空,则加载数据
  127 + if (!val) {
  128 + return;
  129 + }
  130 + try {
  131 + formLoading.value = true
  132 + formData.value = await StudentApi.getStudentContactListByStudentId(val)
  133 + } finally {
  134 + formLoading.value = false
  135 + }
  136 + },
  137 + { immediate: true }
  138 +)
  139 +
  140 +/** 新增按钮操作 */
  141 +const handleAdd = () => {
  142 + const row = {
  143 + id: undefined,
  144 + studentId: undefined,
  145 + name: undefined,
  146 + description: undefined,
  147 + birthday: undefined,
  148 + sex: undefined,
  149 + enabled: undefined,
  150 + avatar: undefined,
  151 + video: undefined,
  152 + memo: undefined
  153 + }
  154 + row.studentId = props.studentId
  155 + formData.value.push(row)
  156 +}
  157 +
  158 +/** 删除按钮操作 */
  159 +const handleDelete = (index) => {
  160 + formData.value.splice(index, 1)
  161 +}
  162 +
  163 +/** 表单校验 */
  164 +const validate = () => {
  165 + return formRef.value.validate()
  166 +}
  167 +
  168 +/** 表单值 */
  169 +const getData = () => {
  170 + return formData.value
  171 +}
  172 +
  173 +defineExpose({ validate, getData })
  174 +</script>
0 175 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/StudentContactList 0 → 100644
  1 +<template>
  2 + <!-- 列表 -->
  3 + <ContentWrap>
  4 + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  5 + <el-table-column label="编号" align="center" prop="id" />
  6 + <el-table-column label="名字" align="center" prop="name" />
  7 + <el-table-column label="简介" align="center" prop="description" />
  8 + <el-table-column
  9 + label="出生日期"
  10 + align="center"
  11 + prop="birthday"
  12 + :formatter="dateFormatter"
  13 + width="180px"
  14 + />
  15 + <el-table-column label="性别" align="center" prop="sex">
  16 + <template #default="scope">
  17 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  18 + </template>
  19 + </el-table-column>
  20 + <el-table-column label="是否有效" align="center" prop="enabled">
  21 + <template #default="scope">
  22 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  23 + </template>
  24 + </el-table-column>
  25 + <el-table-column label="头像" align="center" prop="avatar" />
  26 + <el-table-column label="附件" align="center" prop="video" />
  27 + <el-table-column label="备注" align="center" prop="memo" />
  28 + <el-table-column
  29 + label="创建时间"
  30 + align="center"
  31 + prop="createTime"
  32 + :formatter="dateFormatter"
  33 + width="180px"
  34 + />
  35 + </el-table>
  36 + </ContentWrap>
  37 +</template>
  38 +<script setup lang="ts">
  39 +import { DICT_TYPE } from '@/utils/dict'
  40 +import { dateFormatter } from '@/utils/formatTime'
  41 +import * as StudentApi from '@/api/infra/demo'
  42 +
  43 +const { t } = useI18n() // 国际化
  44 +const message = useMessage() // 消息弹窗
  45 +
  46 +const props = defineProps<{
  47 + studentId: undefined // 学生编号(主表的关联字段)
  48 +}>()
  49 +const loading = ref(false) // 列表的加载中
  50 +const list = ref([]) // 列表的数据
  51 +
  52 +/** 查询列表 */
  53 +const getList = async () => {
  54 + loading.value = true
  55 + try {
  56 + list.value = await StudentApi.getStudentContactListByStudentId(props.studentId)
  57 + } finally {
  58 + loading.value = false
  59 + }
  60 +}
  61 +
  62 +/** 搜索按钮操作 */
  63 +const handleQuery = () => {
  64 + queryParams.pageNo = 1
  65 + getList()
  66 +}
  67 +
  68 +/** 初始化 **/
  69 +onMounted(() => {
  70 + getList()
  71 +})
  72 +</script>
0 73 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/StudentForm 0 → 100644
  1 +<template>
  2 + <Dialog :title="dialogTitle" v-model="dialogVisible">
  3 + <el-form
  4 + ref="formRef"
  5 + :model="formData"
  6 + :rules="formRules"
  7 + label-width="100px"
  8 + v-loading="formLoading"
  9 + >
  10 + <el-form-item label="名字" prop="name">
  11 + <el-input v-model="formData.name" placeholder="请输入名字" />
  12 + </el-form-item>
  13 + <el-form-item label="简介" prop="description">
  14 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  15 + </el-form-item>
  16 + <el-form-item label="出生日期" prop="birthday">
  17 + <el-date-picker
  18 + v-model="formData.birthday"
  19 + type="date"
  20 + value-format="x"
  21 + placeholder="选择出生日期"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item label="性别" prop="sex">
  25 + <el-select v-model="formData.sex" placeholder="请选择性别">
  26 + <el-option
  27 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  28 + :key="dict.value"
  29 + :label="dict.label"
  30 + :value="dict.value"
  31 + />
  32 + </el-select>
  33 + </el-form-item>
  34 + <el-form-item label="是否有效" prop="enabled">
  35 + <el-radio-group v-model="formData.enabled">
  36 + <el-radio
  37 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  38 + :key="dict.value"
  39 + :label="dict.value"
  40 + >
  41 + {{ dict.label }}
  42 + </el-radio>
  43 + </el-radio-group>
  44 + </el-form-item>
  45 + <el-form-item label="头像" prop="avatar">
  46 + <UploadImg v-model="formData.avatar" />
  47 + </el-form-item>
  48 + <el-form-item label="附件" prop="video">
  49 + <UploadFile v-model="formData.video" />
  50 + </el-form-item>
  51 + <el-form-item label="备注" prop="memo">
  52 + <Editor v-model="formData.memo" height="150px" />
  53 + </el-form-item>
  54 + </el-form>
  55 + <!-- 子表的表单 -->
  56 + <el-tabs v-model="subTabsName">
  57 + <el-tab-pane label="学生联系人" name="studentContact">
  58 + <StudentContactForm ref="studentContactFormRef" :student-id="formData.id" />
  59 + </el-tab-pane>
  60 + <el-tab-pane label="学生班主任" name="studentTeacher">
  61 + <StudentTeacherForm ref="studentTeacherFormRef" :student-id="formData.id" />
  62 + </el-tab-pane>
  63 + </el-tabs>
  64 + <template #footer>
  65 + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  66 + <el-button @click="dialogVisible = false">取 消</el-button>
  67 + </template>
  68 + </Dialog>
  69 +</template>
  70 +<script setup lang="ts">
  71 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  72 +import * as StudentApi from '@/api/infra/demo'
  73 +import StudentContactForm from './components/StudentContactForm.vue'
  74 +import StudentTeacherForm from './components/StudentTeacherForm.vue'
  75 +
  76 +const { t } = useI18n() // 国际化
  77 +const message = useMessage() // 消息弹窗
  78 +
  79 +const dialogVisible = ref(false) // 弹窗的是否展示
  80 +const dialogTitle = ref('') // 弹窗的标题
  81 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  82 +const formType = ref('') // 表单的类型:create - 新增;update - 修改
  83 +const formData = ref({
  84 + id: undefined,
  85 + name: undefined,
  86 + description: undefined,
  87 + birthday: undefined,
  88 + sex: undefined,
  89 + enabled: undefined,
  90 + avatar: undefined,
  91 + video: undefined,
  92 + memo: undefined
  93 +})
  94 +const formRules = reactive({
  95 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  96 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  97 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  98 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  99 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  100 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  101 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  102 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  103 +})
  104 +const formRef = ref() // 表单 Ref
  105 +
  106 +/** 子表的表单 */
  107 +const subTabsName = ref('studentContact')
  108 +const studentContactFormRef = ref()
  109 +const studentTeacherFormRef = ref()
  110 +
  111 +/** 打开弹窗 */
  112 +const open = async (type: string, id?: number) => {
  113 + dialogVisible.value = true
  114 + dialogTitle.value = t('action.' + type)
  115 + formType.value = type
  116 + resetForm()
  117 + // 修改时,设置数据
  118 + if (id) {
  119 + formLoading.value = true
  120 + try {
  121 + formData.value = await StudentApi.getStudent(id)
  122 + } finally {
  123 + formLoading.value = false
  124 + }
  125 + }
  126 +}
  127 +defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  128 +
  129 +/** 提交表单 */
  130 +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  131 +const submitForm = async () => {
  132 + // 校验表单
  133 + await formRef.value.validate()
  134 + // 校验子表单
  135 + try {
  136 + await studentContactFormRef.value.validate()
  137 + } catch (e) {
  138 + subTabsName.value = 'studentContact'
  139 + return
  140 + }
  141 + try {
  142 + await studentTeacherFormRef.value.validate()
  143 + } catch (e) {
  144 + subTabsName.value = 'studentTeacher'
  145 + return
  146 + }
  147 + // 提交请求
  148 + formLoading.value = true
  149 + try {
  150 + const data = formData.value as unknown as StudentApi.StudentVO
  151 + // 拼接子表的数据
  152 + data.studentContacts = studentContactFormRef.value.getData()
  153 + data.studentTeacher = studentTeacherFormRef.value.getData()
  154 + if (formType.value === 'create') {
  155 + await StudentApi.createStudent(data)
  156 + message.success(t('common.createSuccess'))
  157 + } else {
  158 + await StudentApi.updateStudent(data)
  159 + message.success(t('common.updateSuccess'))
  160 + }
  161 + dialogVisible.value = false
  162 + // 发送操作成功的事件
  163 + emit('success')
  164 + } finally {
  165 + formLoading.value = false
  166 + }
  167 +}
  168 +
  169 +/** 重置表单 */
  170 +const resetForm = () => {
  171 + formData.value = {
  172 + id: undefined,
  173 + name: undefined,
  174 + description: undefined,
  175 + birthday: undefined,
  176 + sex: undefined,
  177 + enabled: undefined,
  178 + avatar: undefined,
  179 + video: undefined,
  180 + memo: undefined
  181 + }
  182 + formRef.value?.resetFields()
  183 +}
  184 +</script>
0 185 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/StudentTeacherForm 0 → 100644
  1 +<template>
  2 + <el-form
  3 + ref="formRef"
  4 + :model="formData"
  5 + :rules="formRules"
  6 + label-width="100px"
  7 + v-loading="formLoading"
  8 + >
  9 + <el-form-item label="名字" prop="name">
  10 + <el-input v-model="formData.name" placeholder="请输入名字" />
  11 + </el-form-item>
  12 + <el-form-item label="简介" prop="description">
  13 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  14 + </el-form-item>
  15 + <el-form-item label="出生日期" prop="birthday">
  16 + <el-date-picker
  17 + v-model="formData.birthday"
  18 + type="date"
  19 + value-format="x"
  20 + placeholder="选择出生日期"
  21 + />
  22 + </el-form-item>
  23 + <el-form-item label="性别" prop="sex">
  24 + <el-select v-model="formData.sex" placeholder="请选择性别">
  25 + <el-option
  26 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  27 + :key="dict.value"
  28 + :label="dict.label"
  29 + :value="dict.value"
  30 + />
  31 + </el-select>
  32 + </el-form-item>
  33 + <el-form-item label="是否有效" prop="enabled">
  34 + <el-radio-group v-model="formData.enabled">
  35 + <el-radio
  36 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  37 + :key="dict.value"
  38 + :label="dict.value"
  39 + >
  40 + {{ dict.label }}
  41 + </el-radio>
  42 + </el-radio-group>
  43 + </el-form-item>
  44 + <el-form-item label="头像" prop="avatar">
  45 + <UploadImg v-model="formData.avatar" />
  46 + </el-form-item>
  47 + <el-form-item label="附件" prop="video">
  48 + <UploadFile v-model="formData.video" />
  49 + </el-form-item>
  50 + <el-form-item label="备注" prop="memo">
  51 + <Editor v-model="formData.memo" height="150px" />
  52 + </el-form-item>
  53 + </el-form>
  54 +</template>
  55 +<script setup lang="ts">
  56 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  57 +import * as StudentApi from '@/api/infra/demo'
  58 +
  59 +const props = defineProps<{
  60 + studentId: undefined // 学生编号(主表的关联字段)
  61 +}>()
  62 +const formLoading = ref(false) // 表单的加载中
  63 +const formData = ref([])
  64 +const formRules = reactive({
  65 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  66 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  67 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  68 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  69 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  70 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  71 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  72 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  73 +})
  74 +const formRef = ref() // 表单 Ref
  75 +
  76 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  77 +watch(
  78 + () => props.studentId,
  79 + async (val) => {
  80 + // 1. 重置表单
  81 + formData.value = {
  82 + id: undefined,
  83 + studentId: undefined,
  84 + name: undefined,
  85 + description: undefined,
  86 + birthday: undefined,
  87 + sex: undefined,
  88 + enabled: undefined,
  89 + avatar: undefined,
  90 + video: undefined,
  91 + memo: undefined,
  92 + }
  93 + // 2. val 非空,则加载数据
  94 + if (!val) {
  95 + return;
  96 + }
  97 + try {
  98 + formLoading.value = true
  99 + const data = await StudentApi.getStudentTeacherByStudentId(val)
  100 + if (!data) {
  101 + return
  102 + }
  103 + formData.value = data
  104 + } finally {
  105 + formLoading.value = false
  106 + }
  107 + },
  108 + { immediate: true }
  109 +)
  110 +
  111 +/** 表单校验 */
  112 +const validate = () => {
  113 + return formRef.value.validate()
  114 +}
  115 +
  116 +/** 表单值 */
  117 +const getData = () => {
  118 + return formData.value
  119 +}
  120 +
  121 +defineExpose({ validate, getData })
  122 +</script>
0 123 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/StudentTeacherList 0 → 100644
  1 +<template>
  2 + <!-- 列表 -->
  3 + <ContentWrap>
  4 + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  5 + <el-table-column label="编号" align="center" prop="id" />
  6 + <el-table-column label="名字" align="center" prop="name" />
  7 + <el-table-column label="简介" align="center" prop="description" />
  8 + <el-table-column
  9 + label="出生日期"
  10 + align="center"
  11 + prop="birthday"
  12 + :formatter="dateFormatter"
  13 + width="180px"
  14 + />
  15 + <el-table-column label="性别" align="center" prop="sex">
  16 + <template #default="scope">
  17 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  18 + </template>
  19 + </el-table-column>
  20 + <el-table-column label="是否有效" align="center" prop="enabled">
  21 + <template #default="scope">
  22 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  23 + </template>
  24 + </el-table-column>
  25 + <el-table-column label="头像" align="center" prop="avatar" />
  26 + <el-table-column label="附件" align="center" prop="video" />
  27 + <el-table-column label="备注" align="center" prop="memo" />
  28 + <el-table-column
  29 + label="创建时间"
  30 + align="center"
  31 + prop="createTime"
  32 + :formatter="dateFormatter"
  33 + width="180px"
  34 + />
  35 + </el-table>
  36 + </ContentWrap>
  37 +</template>
  38 +<script setup lang="ts">
  39 +import { DICT_TYPE } from '@/utils/dict'
  40 +import { dateFormatter } from '@/utils/formatTime'
  41 +import * as StudentApi from '@/api/infra/demo'
  42 +
  43 +const { t } = useI18n() // 国际化
  44 +const message = useMessage() // 消息弹窗
  45 +
  46 +const props = defineProps<{
  47 + studentId: undefined // 学生编号(主表的关联字段)
  48 +}>()
  49 +const loading = ref(false) // 列表的加载中
  50 +const list = ref([]) // 列表的数据
  51 +
  52 +/** 查询列表 */
  53 +const getList = async () => {
  54 + loading.value = true
  55 + try {
  56 + const data = await StudentApi.getStudentTeacherByStudentId(props.studentId)
  57 + if (!data) {
  58 + return
  59 + }
  60 + list.value.push(data)
  61 + } finally {
  62 + loading.value = false
  63 + }
  64 +}
  65 +
  66 +/** 搜索按钮操作 */
  67 +const handleQuery = () => {
  68 + queryParams.pageNo = 1
  69 + getList()
  70 +}
  71 +
  72 +/** 初始化 **/
  73 +onMounted(() => {
  74 + getList()
  75 +})
  76 +</script>
0 77 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/vue/index 0 → 100644
  1 +<template>
  2 + <ContentWrap>
  3 + <!-- 搜索工作栏 -->
  4 + <el-form
  5 + class="-mb-15px"
  6 + :model="queryParams"
  7 + ref="queryFormRef"
  8 + :inline="true"
  9 + label-width="68px"
  10 + >
  11 + <el-form-item label="名字" prop="name">
  12 + <el-input
  13 + v-model="queryParams.name"
  14 + placeholder="请输入名字"
  15 + clearable
  16 + @keyup.enter="handleQuery"
  17 + class="!w-240px"
  18 + />
  19 + </el-form-item>
  20 + <el-form-item label="出生日期" prop="birthday">
  21 + <el-date-picker
  22 + v-model="queryParams.birthday"
  23 + value-format="YYYY-MM-DD"
  24 + type="date"
  25 + placeholder="选择出生日期"
  26 + clearable
  27 + class="!w-240px"
  28 + />
  29 + </el-form-item>
  30 + <el-form-item label="性别" prop="sex">
  31 + <el-select
  32 + v-model="queryParams.sex"
  33 + placeholder="请选择性别"
  34 + clearable
  35 + class="!w-240px"
  36 + >
  37 + <el-option
  38 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  39 + :key="dict.value"
  40 + :label="dict.label"
  41 + :value="dict.value"
  42 + />
  43 + </el-select>
  44 + </el-form-item>
  45 + <el-form-item label="是否有效" prop="enabled">
  46 + <el-select
  47 + v-model="queryParams.enabled"
  48 + placeholder="请选择是否有效"
  49 + clearable
  50 + class="!w-240px"
  51 + >
  52 + <el-option
  53 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  54 + :key="dict.value"
  55 + :label="dict.label"
  56 + :value="dict.value"
  57 + />
  58 + </el-select>
  59 + </el-form-item>
  60 + <el-form-item label="创建时间" prop="createTime">
  61 + <el-date-picker
  62 + v-model="queryParams.createTime"
  63 + value-format="YYYY-MM-DD HH:mm:ss"
  64 + type="daterange"
  65 + start-placeholder="开始日期"
  66 + end-placeholder="结束日期"
  67 + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  68 + class="!w-240px"
  69 + />
  70 + </el-form-item>
  71 + <el-form-item>
  72 + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
  73 + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
  74 + <el-button
  75 + type="primary"
  76 + plain
  77 + @click="openForm('create')"
  78 + v-hasPermi="['infra:student:create']"
  79 + >
  80 + <Icon icon="ep:plus" class="mr-5px" /> 新增
  81 + </el-button>
  82 + <el-button
  83 + type="success"
  84 + plain
  85 + @click="handleExport"
  86 + :loading="exportLoading"
  87 + v-hasPermi="['infra:student:export']"
  88 + >
  89 + <Icon icon="ep:download" class="mr-5px" /> 导出
  90 + </el-button>
  91 + </el-form-item>
  92 + </el-form>
  93 + </ContentWrap>
  94 +
  95 + <!-- 列表 -->
  96 + <ContentWrap>
  97 + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  98 + <!-- 子表的列表 -->
  99 + <el-table-column type="expand">
  100 + <template #default="scope">
  101 + <el-tabs model-value="studentContact">
  102 + <el-tab-pane label="学生联系人" name="studentContact">
  103 + <StudentContactList :student-id="scope.row.id" />
  104 + </el-tab-pane>
  105 + <el-tab-pane label="学生班主任" name="studentTeacher">
  106 + <StudentTeacherList :student-id="scope.row.id" />
  107 + </el-tab-pane>
  108 + </el-tabs>
  109 + </template>
  110 + </el-table-column>
  111 + <el-table-column label="编号" align="center" prop="id" />
  112 + <el-table-column label="名字" align="center" prop="name" />
  113 + <el-table-column label="简介" align="center" prop="description" />
  114 + <el-table-column
  115 + label="出生日期"
  116 + align="center"
  117 + prop="birthday"
  118 + :formatter="dateFormatter"
  119 + width="180px"
  120 + />
  121 + <el-table-column label="性别" align="center" prop="sex">
  122 + <template #default="scope">
  123 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  124 + </template>
  125 + </el-table-column>
  126 + <el-table-column label="是否有效" align="center" prop="enabled">
  127 + <template #default="scope">
  128 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  129 + </template>
  130 + </el-table-column>
  131 + <el-table-column label="头像" align="center" prop="avatar" />
  132 + <el-table-column label="附件" align="center" prop="video" />
  133 + <el-table-column label="备注" align="center" prop="memo" />
  134 + <el-table-column
  135 + label="创建时间"
  136 + align="center"
  137 + prop="createTime"
  138 + :formatter="dateFormatter"
  139 + width="180px"
  140 + />
  141 + <el-table-column label="操作" align="center">
  142 + <template #default="scope">
  143 + <el-button
  144 + link
  145 + type="primary"
  146 + @click="openForm('update', scope.row.id)"
  147 + v-hasPermi="['infra:student:update']"
  148 + >
  149 + 编辑
  150 + </el-button>
  151 + <el-button
  152 + link
  153 + type="danger"
  154 + @click="handleDelete(scope.row.id)"
  155 + v-hasPermi="['infra:student:delete']"
  156 + >
  157 + 删除
  158 + </el-button>
  159 + </template>
  160 + </el-table-column>
  161 + </el-table>
  162 + <!-- 分页 -->
  163 + <Pagination
  164 + :total="total"
  165 + v-model:page="queryParams.pageNo"
  166 + v-model:limit="queryParams.pageSize"
  167 + @pagination="getList"
  168 + />
  169 + </ContentWrap>
  170 +
  171 + <!-- 表单弹窗:添加/修改 -->
  172 + <StudentForm ref="formRef" @success="getList" />
  173 +</template>
  174 +
  175 +<script setup lang="ts">
  176 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  177 +import { dateFormatter } from '@/utils/formatTime'
  178 +import download from '@/utils/download'
  179 +import * as StudentApi from '@/api/infra/demo'
  180 +import StudentForm from './StudentForm.vue'
  181 +import StudentContactList from './components/StudentContactList.vue'
  182 +import StudentTeacherList from './components/StudentTeacherList.vue'
  183 +
  184 +defineOptions({ name: 'InfraStudent' })
  185 +
  186 +const message = useMessage() // 消息弹窗
  187 +const { t } = useI18n() // 国际化
  188 +
  189 +const loading = ref(true) // 列表的加载中
  190 +const list = ref([]) // 列表的数据
  191 +const total = ref(0) // 列表的总页数
  192 +const queryParams = reactive({
  193 + pageNo: 1,
  194 + pageSize: 10,
  195 + name: null,
  196 + birthday: null,
  197 + birthday: [],
  198 + sex: null,
  199 + enabled: null,
  200 + createTime: []
  201 +})
  202 +const queryFormRef = ref() // 搜索的表单
  203 +const exportLoading = ref(false) // 导出的加载中
  204 +
  205 +/** 查询列表 */
  206 +const getList = async () => {
  207 + loading.value = true
  208 + try {
  209 + const data = await StudentApi.getStudentPage(queryParams)
  210 + list.value = data.list
  211 + total.value = data.total
  212 + } finally {
  213 + loading.value = false
  214 + }
  215 +}
  216 +
  217 +/** 搜索按钮操作 */
  218 +const handleQuery = () => {
  219 + queryParams.pageNo = 1
  220 + getList()
  221 +}
  222 +
  223 +/** 重置按钮操作 */
  224 +const resetQuery = () => {
  225 + queryFormRef.value.resetFields()
  226 + handleQuery()
  227 +}
  228 +
  229 +/** 添加/修改操作 */
  230 +const formRef = ref()
  231 +const openForm = (type: string, id?: number) => {
  232 + formRef.value.open(type, id)
  233 +}
  234 +
  235 +/** 删除按钮操作 */
  236 +const handleDelete = async (id: number) => {
  237 + try {
  238 + // 删除的二次确认
  239 + await message.delConfirm()
  240 + // 发起删除
  241 + await StudentApi.deleteStudent(id)
  242 + message.success(t('common.delSuccess'))
  243 + // 刷新列表
  244 + await getList()
  245 + } catch {}
  246 +}
  247 +
  248 +/** 导出按钮操作 */
  249 +const handleExport = async () => {
  250 + try {
  251 + // 导出的二次确认
  252 + await message.exportConfirm()
  253 + // 发起导出
  254 + exportLoading.value = true
  255 + const data = await StudentApi.exportStudent(queryParams)
  256 + download.excel(data, '学生.xls')
  257 + } catch {
  258 + } finally {
  259 + exportLoading.value = false
  260 + }
  261 +}
  262 +
  263 +/** 初始化 **/
  264 +onMounted(() => {
  265 + getList()
  266 +})
  267 +</script>
0 268 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_inner/xml/InfraStudentMapper 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentController",
  12 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentDO",
  15 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentContactDO",
  18 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentContactDO.java"
  19 +}, {
  20 + "contentPath" : "java/InfraStudentTeacherDO",
  21 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentTeacherDO.java"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentMapper",
  24 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  25 +}, {
  26 + "contentPath" : "java/InfraStudentContactMapper",
  27 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentContactMapper.java"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentTeacherMapper",
  30 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentTeacherMapper.java"
  31 +}, {
  32 + "contentPath" : "xml/InfraStudentMapper",
  33 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  34 +}, {
  35 + "contentPath" : "java/InfraStudentServiceImpl",
  36 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  37 +}, {
  38 + "contentPath" : "java/InfraStudentService",
  39 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  40 +}, {
  41 + "contentPath" : "java/InfraStudentServiceImplTest",
  42 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  43 +}, {
  44 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  45 + "filePath" : "yudao-module-infra/yudao-module-infra-api/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-vue3/src/views/infra/demo/index.vue"
  55 +}, {
  56 + "contentPath" : "vue/StudentForm",
  57 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/StudentForm.vue"
  58 +}, {
  59 + "contentPath" : "vue/StudentContactForm",
  60 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentContactForm.vue"
  61 +}, {
  62 + "contentPath" : "vue/StudentTeacherForm",
  63 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/components/StudentTeacherForm.vue"
  64 +}, {
  65 + "contentPath" : "ts/index",
  66 + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts"
  67 +} ]
0 68 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/ErrorCodeConstants_手动操作 0 → 100644
  1 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  2 +// ========== 学生 TODO 补充编号 ==========
  3 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
0 4 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentContactDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生联系人 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student_contact")
  16 +@KeySequence("infra_student_contact_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentContactDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 学生编号
  32 + */
  33 + private Long studentId;
  34 + /**
  35 + * 名字
  36 + */
  37 + private String name;
  38 + /**
  39 + * 简介
  40 + */
  41 + private String description;
  42 + /**
  43 + * 出生日期
  44 + */
  45 + private LocalDateTime birthday;
  46 + /**
  47 + * 性别
  48 + *
  49 + * 枚举 {@link TODO system_user_sex 对应的类}
  50 + */
  51 + private Integer sex;
  52 + /**
  53 + * 是否有效
  54 + *
  55 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  56 + */
  57 + private Boolean enabled;
  58 + /**
  59 + * 头像
  60 + */
  61 + private String avatar;
  62 + /**
  63 + * 附件
  64 + */
  65 + private String video;
  66 + /**
  67 + * 备注
  68 + */
  69 + private String memo;
  70 +
  71 +}
0 72 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentContactMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +/**
  13 + * 学生联系人 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentContactMapper extends BaseMapperX<InfraStudentContactDO> {
  19 +
  20 + default List<InfraStudentContactDO> selectListByStudentId(Long studentId) {
  21 + return selectList(InfraStudentContactDO::getStudentId, studentId);
  22 + }
  23 +
  24 + default int deleteByStudentId(Long studentId) {
  25 + return delete(InfraStudentContactDO::getStudentId, studentId);
  26 + }
  27 +
  28 +}
0 29 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.security.access.prepost.PreAuthorize;
  7 +import io.swagger.v3.oas.annotations.tags.Tag;
  8 +import io.swagger.v3.oas.annotations.Parameter;
  9 +import io.swagger.v3.oas.annotations.Operation;
  10 +
  11 +import javax.validation.constraints.*;
  12 +import javax.validation.*;
  13 +import javax.servlet.http.*;
  14 +import java.util.*;
  15 +import java.io.IOException;
  16 +
  17 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  18 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  19 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  20 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  24 +
  25 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  26 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  27 +
  28 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  29 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  30 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  31 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  32 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  33 +
  34 +@Tag(name = "管理后台 - 学生")
  35 +@RestController
  36 +@RequestMapping("/infra/student")
  37 +@Validated
  38 +public class InfraStudentController {
  39 +
  40 + @Resource
  41 + private InfraStudentService studentService;
  42 +
  43 + @PostMapping("/create")
  44 + @Operation(summary = "创建学生")
  45 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  46 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  47 + return success(studentService.createStudent(createReqVO));
  48 + }
  49 +
  50 + @PutMapping("/update")
  51 + @Operation(summary = "更新学生")
  52 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  53 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  54 + studentService.updateStudent(updateReqVO);
  55 + return success(true);
  56 + }
  57 +
  58 + @DeleteMapping("/delete")
  59 + @Operation(summary = "删除学生")
  60 + @Parameter(name = "id", description = "编号", required = true)
  61 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  62 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  63 + studentService.deleteStudent(id);
  64 + return success(true);
  65 + }
  66 +
  67 + @GetMapping("/get")
  68 + @Operation(summary = "获得学生")
  69 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  70 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  71 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  72 + InfraStudentDO student = studentService.getStudent(id);
  73 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  74 + }
  75 +
  76 + @GetMapping("/page")
  77 + @Operation(summary = "获得学生分页")
  78 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  79 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  80 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  81 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  82 + }
  83 +
  84 + @GetMapping("/export-excel")
  85 + @Operation(summary = "导出学生 Excel")
  86 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  87 + @OperateLog(type = EXPORT)
  88 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  89 + HttpServletResponse response) throws IOException {
  90 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  91 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  92 + // 导出 Excel
  93 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  94 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  95 + }
  96 +
  97 + // ==================== 子表(学生联系人) ====================
  98 +
  99 + @GetMapping("/student-contact/list-by-student-id")
  100 + @Operation(summary = "获得学生联系人列表")
  101 + @Parameter(name = "studentId", description = "学生编号")
  102 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  103 + public CommonResult<List<InfraStudentContactDO>> getStudentContactListByStudentId(@RequestParam("studentId") Long studentId) {
  104 + return success(studentService.getStudentContactListByStudentId(studentId));
  105 + }
  106 +
  107 + // ==================== 子表(学生班主任) ====================
  108 +
  109 + @GetMapping("/student-teacher/get-by-student-id")
  110 + @Operation(summary = "获得学生班主任")
  111 + @Parameter(name = "studentId", description = "学生编号")
  112 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  113 + public CommonResult<InfraStudentTeacherDO> getStudentTeacherByStudentId(@RequestParam("studentId") Long studentId) {
  114 + return success(studentService.getStudentTeacherByStudentId(studentId));
  115 + }
  116 +
  117 +}
0 118 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +}
0 68 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class InfraStudentPageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "名字", example = "芋头")
  19 + private String name;
  20 +
  21 + @Schema(description = "出生日期")
  22 + private LocalDateTime birthday;
  23 +
  24 + @Schema(description = "性别", example = "1")
  25 + private Integer sex;
  26 +
  27 + @Schema(description = "是否有效", example = "true")
  28 + private Boolean enabled;
  29 +
  30 + @Schema(description = "创建时间")
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + private LocalDateTime[] createTime;
  33 +
  34 +}
0 35 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import java.util.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +import com.alibaba.excel.annotation.*;
  10 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  11 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  12 +
  13 +@Schema(description = "管理后台 - 学生 Response VO")
  14 +@Data
  15 +@ExcelIgnoreUnannotated
  16 +public class InfraStudentRespVO {
  17 +
  18 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  19 + @ExcelProperty("编号")
  20 + private Long id;
  21 +
  22 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  23 + @ExcelProperty("名字")
  24 + private String name;
  25 +
  26 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  27 + @ExcelProperty("简介")
  28 + private String description;
  29 +
  30 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + @ExcelProperty("出生日期")
  32 + private LocalDateTime birthday;
  33 +
  34 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  35 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  36 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  37 + private Integer sex;
  38 +
  39 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  40 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  41 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  42 + private Boolean enabled;
  43 +
  44 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  45 + @ExcelProperty("头像")
  46 + private String avatar;
  47 +
  48 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  49 + @ExcelProperty("附件")
  50 + private String video;
  51 +
  52 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  53 + @ExcelProperty("备注")
  54 + private String memo;
  55 +
  56 + @Schema(description = "创建时间")
  57 + @ExcelProperty("创建时间")
  58 + private LocalDateTime createTime;
  59 +
  60 +}
0 61 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import javax.validation.constraints.*;
  7 +import java.util.*;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +import java.time.LocalDateTime;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  12 +
  13 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  14 +@Data
  15 +public class InfraStudentSaveReqVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + private Long id;
  19 +
  20 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  21 + @NotEmpty(message = "名字不能为空")
  22 + private String name;
  23 +
  24 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  25 + @NotEmpty(message = "简介不能为空")
  26 + private String description;
  27 +
  28 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  29 + @NotNull(message = "出生日期不能为空")
  30 + private LocalDateTime birthday;
  31 +
  32 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  33 + @NotNull(message = "性别不能为空")
  34 + private Integer sex;
  35 +
  36 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  37 + @NotNull(message = "是否有效不能为空")
  38 + private Boolean enabled;
  39 +
  40 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  41 + @NotEmpty(message = "头像不能为空")
  42 + private String avatar;
  43 +
  44 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  45 + @NotEmpty(message = "附件不能为空")
  46 + private String video;
  47 +
  48 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  49 + @NotEmpty(message = "备注不能为空")
  50 + private String memo;
  51 +
  52 + @Schema(description = "学生联系人列表")
  53 + private List<InfraStudentContactDO> studentContacts;
  54 +
  55 + @Schema(description = "学生班主任")
  56 + private InfraStudentTeacherDO studentTeacher;
  57 +
  58 +}
0 59 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import javax.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  9 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  10 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  11 +
  12 +/**
  13 + * 学生 Service 接口
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +public interface InfraStudentService {
  18 +
  19 + /**
  20 + * 创建学生
  21 + *
  22 + * @param createReqVO 创建信息
  23 + * @return 编号
  24 + */
  25 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
  26 +
  27 + /**
  28 + * 更新学生
  29 + *
  30 + * @param updateReqVO 更新信息
  31 + */
  32 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
  33 +
  34 + /**
  35 + * 删除学生
  36 + *
  37 + * @param id 编号
  38 + */
  39 + void deleteStudent(Long id);
  40 +
  41 + /**
  42 + * 获得学生
  43 + *
  44 + * @param id 编号
  45 + * @return 学生
  46 + */
  47 + InfraStudentDO getStudent(Long id);
  48 +
  49 + /**
  50 + * 获得学生分页
  51 + *
  52 + * @param pageReqVO 分页查询
  53 + * @return 学生分页
  54 + */
  55 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  56 +
  57 + // ==================== 子表(学生联系人) ====================
  58 +
  59 + /**
  60 + * 获得学生联系人列表
  61 + *
  62 + * @param studentId 学生编号
  63 + * @return 学生联系人列表
  64 + */
  65 + List<InfraStudentContactDO> getStudentContactListByStudentId(Long studentId);
  66 +
  67 + // ==================== 子表(学生班主任) ====================
  68 +
  69 + /**
  70 + * 获得学生班主任
  71 + *
  72 + * @param studentId 学生编号
  73 + * @return 学生班主任
  74 + */
  75 + InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId);
  76 +
  77 +}
0 78 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.transaction.annotation.Transactional;
  7 +
  8 +import java.util.*;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  11 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentContactDO;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  13 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  15 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  16 +
  17 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  18 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentContactMapper;
  19 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentTeacherMapper;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * 学生 Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class InfraStudentServiceImpl implements InfraStudentService {
  32 +
  33 + @Resource
  34 + private InfraStudentMapper studentMapper;
  35 + @Resource
  36 + private InfraStudentContactMapper studentContactMapper;
  37 + @Resource
  38 + private InfraStudentTeacherMapper studentTeacherMapper;
  39 +
  40 + @Override
  41 + @Transactional(rollbackFor = Exception.class)
  42 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  43 + // 插入
  44 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  45 + studentMapper.insert(student);
  46 +
  47 + // 插入子表
  48 + createStudentContactList(student.getId(), createReqVO.getStudentContacts());
  49 + createStudentTeacher(student.getId(), createReqVO.getStudentTeacher());
  50 + // 返回
  51 + return student.getId();
  52 + }
  53 +
  54 + @Override
  55 + @Transactional(rollbackFor = Exception.class)
  56 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  57 + // 校验存在
  58 + validateStudentExists(updateReqVO.getId());
  59 + // 更新
  60 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  61 + studentMapper.updateById(updateObj);
  62 +
  63 + // 更新子表
  64 + updateStudentContactList(updateReqVO.getId(), updateReqVO.getStudentContacts());
  65 + updateStudentTeacher(updateReqVO.getId(), updateReqVO.getStudentTeacher());
  66 + }
  67 +
  68 + @Override
  69 + @Transactional(rollbackFor = Exception.class)
  70 + public void deleteStudent(Long id) {
  71 + // 校验存在
  72 + validateStudentExists(id);
  73 + // 删除
  74 + studentMapper.deleteById(id);
  75 +
  76 + // 删除子表
  77 + deleteStudentContactByStudentId(id);
  78 + deleteStudentTeacherByStudentId(id);
  79 + }
  80 +
  81 + private void validateStudentExists(Long id) {
  82 + if (studentMapper.selectById(id) == null) {
  83 + throw exception(STUDENT_NOT_EXISTS);
  84 + }
  85 + }
  86 +
  87 + @Override
  88 + public InfraStudentDO getStudent(Long id) {
  89 + return studentMapper.selectById(id);
  90 + }
  91 +
  92 + @Override
  93 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  94 + return studentMapper.selectPage(pageReqVO);
  95 + }
  96 +
  97 + // ==================== 子表(学生联系人) ====================
  98 +
  99 + @Override
  100 + public List<InfraStudentContactDO> getStudentContactListByStudentId(Long studentId) {
  101 + return studentContactMapper.selectListByStudentId(studentId);
  102 + }
  103 +
  104 + private void createStudentContactList(Long studentId, List<InfraStudentContactDO> list) {
  105 + list.forEach(o -> o.setStudentId(studentId));
  106 + studentContactMapper.insertBatch(list);
  107 + }
  108 +
  109 + 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);
  113 + }
  114 +
  115 + private void deleteStudentContactByStudentId(Long studentId) {
  116 + studentContactMapper.deleteByStudentId(studentId);
  117 + }
  118 +
  119 + // ==================== 子表(学生班主任) ====================
  120 +
  121 + @Override
  122 + public InfraStudentTeacherDO getStudentTeacherByStudentId(Long studentId) {
  123 + return studentTeacherMapper.selectByStudentId(studentId);
  124 + }
  125 +
  126 + private void createStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) {
  127 + if (studentTeacher == null) {
  128 + return;
  129 + }
  130 + studentTeacher.setStudentId(studentId);
  131 + studentTeacherMapper.insert(studentTeacher);
  132 + }
  133 +
  134 + private void updateStudentTeacher(Long studentId, InfraStudentTeacherDO studentTeacher) {
  135 + if (studentTeacher == null) {
  136 + return;
  137 + }
  138 + studentTeacher.setStudentId(studentId);
  139 + studentTeacher.setUpdater(null).setUpdateTime(null); // 解决更新情况下:updateTime 不更新
  140 + studentTeacherMapper.insertOrUpdate(studentTeacher);
  141 + }
  142 +
  143 + private void deleteStudentTeacherByStudentId(Long studentId) {
  144 + studentTeacherMapper.deleteByStudentId(studentId);
  145 + }
  146 +
  147 +}
0 148 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.boot.test.mock.mockito.MockBean;
  6 +
  7 +import javax.annotation.Resource;
  8 +
  9 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  10 +
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  15 +
  16 +import javax.annotation.Resource;
  17 +import org.springframework.context.annotation.Import;
  18 +import java.util.*;
  19 +import java.time.LocalDateTime;
  20 +
  21 +import static cn.hutool.core.util.RandomUtil.*;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  24 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  27 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  28 +import static org.junit.jupiter.api.Assertions.*;
  29 +import static org.mockito.Mockito.*;
  30 +
  31 +/**
  32 + * {@link InfraStudentServiceImpl} 的单元测试类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Import(InfraStudentServiceImpl.class)
  37 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  38 +
  39 + @Resource
  40 + private InfraStudentServiceImpl studentService;
  41 +
  42 + @Resource
  43 + private InfraStudentMapper studentMapper;
  44 +
  45 + @Test
  46 + public void testCreateStudent_success() {
  47 + // 准备参数
  48 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  49 +
  50 + // 调用
  51 + Long studentId = studentService.createStudent(createReqVO);
  52 + // 断言
  53 + assertNotNull(studentId);
  54 + // 校验记录的属性是否正确
  55 + InfraStudentDO student = studentMapper.selectById(studentId);
  56 + assertPojoEquals(createReqVO, student, "id");
  57 + }
  58 +
  59 + @Test
  60 + public void testUpdateStudent_success() {
  61 + // mock 数据
  62 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  63 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  64 + // 准备参数
  65 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  66 + o.setId(dbStudent.getId()); // 设置更新的 ID
  67 + });
  68 +
  69 + // 调用
  70 + studentService.updateStudent(updateReqVO);
  71 + // 校验是否更新正确
  72 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  73 + assertPojoEquals(updateReqVO, student);
  74 + }
  75 +
  76 + @Test
  77 + public void testUpdateStudent_notExists() {
  78 + // 准备参数
  79 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  80 +
  81 + // 调用, 并断言异常
  82 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  83 + }
  84 +
  85 + @Test
  86 + public void testDeleteStudent_success() {
  87 + // mock 数据
  88 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  89 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  90 + // 准备参数
  91 + Long id = dbStudent.getId();
  92 +
  93 + // 调用
  94 + studentService.deleteStudent(id);
  95 + // 校验数据不存在了
  96 + assertNull(studentMapper.selectById(id));
  97 + }
  98 +
  99 + @Test
  100 + public void testDeleteStudent_notExists() {
  101 + // 准备参数
  102 + Long id = randomLongId();
  103 +
  104 + // 调用, 并断言异常
  105 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  106 + }
  107 +
  108 + @Test
  109 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  110 + public void testGetStudentPage() {
  111 + // mock 数据
  112 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  113 + o.setName(null);
  114 + o.setBirthday(null);
  115 + o.setSex(null);
  116 + o.setEnabled(null);
  117 + o.setCreateTime(null);
  118 + });
  119 + studentMapper.insert(dbStudent);
  120 + // 测试 name 不匹配
  121 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  122 + // 测试 birthday 不匹配
  123 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  124 + // 测试 sex 不匹配
  125 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  126 + // 测试 enabled 不匹配
  127 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  128 + // 测试 createTime 不匹配
  129 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  130 + // 准备参数
  131 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  132 + reqVO.setName(null);
  133 + reqVO.setBirthday(null);
  134 + reqVO.setSex(null);
  135 + reqVO.setEnabled(null);
  136 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  137 +
  138 + // 调用
  139 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  140 + // 断言
  141 + assertEquals(1, pageResult.getTotal());
  142 + assertEquals(1, pageResult.getList().size());
  143 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  144 + }
  145 +
  146 +}
0 147 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentTeacherDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生班主任 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student_teacher")
  16 +@KeySequence("infra_student_teacher_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentTeacherDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 学生编号
  32 + */
  33 + private Long studentId;
  34 + /**
  35 + * 名字
  36 + */
  37 + private String name;
  38 + /**
  39 + * 简介
  40 + */
  41 + private String description;
  42 + /**
  43 + * 出生日期
  44 + */
  45 + private LocalDateTime birthday;
  46 + /**
  47 + * 性别
  48 + *
  49 + * 枚举 {@link TODO system_user_sex 对应的类}
  50 + */
  51 + private Integer sex;
  52 + /**
  53 + * 是否有效
  54 + *
  55 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  56 + */
  57 + private Boolean enabled;
  58 + /**
  59 + * 头像
  60 + */
  61 + private String avatar;
  62 + /**
  63 + * 附件
  64 + */
  65 + private String video;
  66 + /**
  67 + * 备注
  68 + */
  69 + private String memo;
  70 +
  71 +}
0 72 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/java/InfraStudentTeacherMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  8 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  9 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentTeacherDO;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +/**
  13 + * 学生班主任 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentTeacherMapper extends BaseMapperX<InfraStudentTeacherDO> {
  19 +
  20 + default InfraStudentTeacherDO selectByStudentId(Long studentId) {
  21 + return selectOne(InfraStudentTeacherDO::getStudentId, studentId);
  22 + }
  23 +
  24 + default int deleteByStudentId(Long studentId) {
  25 + return delete(InfraStudentTeacherDO::getStudentId, studentId);
  26 + }
  27 +
  28 +}
0 29 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +-- 暂时只支持 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 +);
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/ts/index 0 → 100644
  1 +import request from '@/config/axios'
  2 +
  3 +export interface StudentVO {
  4 + id: number
  5 + name: string
  6 + description: string
  7 + birthday: Date
  8 + sex: number
  9 + enabled: boolean
  10 + avatar: string
  11 + video: string
  12 + memo: string
  13 +}
  14 +
  15 +// 查询学生分页
  16 +export const getStudentPage = async (params) => {
  17 + return await request.get({ url: `/infra/student/page`, params })
  18 +}
  19 +
  20 +// 查询学生详情
  21 +export const getStudent = async (id: number) => {
  22 + return await request.get({ url: `/infra/student/get?id=` + id })
  23 +}
  24 +
  25 +// 新增学生
  26 +export const createStudent = async (data: StudentVO) => {
  27 + return await request.post({ url: `/infra/student/create`, data })
  28 +}
  29 +
  30 +// 修改学生
  31 +export const updateStudent = async (data: StudentVO) => {
  32 + return await request.put({ url: `/infra/student/update`, data })
  33 +}
  34 +
  35 +// 删除学生
  36 +export const deleteStudent = async (id: number) => {
  37 + return await request.delete({ url: `/infra/student/delete?id=` + id })
  38 +}
  39 +
  40 +// 导出学生 Excel
  41 +export const exportStudent = async (params) => {
  42 + return await request.download({ url: `/infra/student/export-excel`, params })
  43 +}
  44 +
  45 +// ==================== 子表(学生联系人) ====================
  46 +
  47 +// 获得学生联系人列表
  48 +export const getStudentContactListByStudentId = async (studentId) => {
  49 + return await request.get({ url: `/infra/student/student-contact/list-by-student-id?studentId=` + studentId })
  50 +}
  51 +
  52 +// ==================== 子表(学生班主任) ====================
  53 +
  54 +// 获得学生班主任
  55 +export const getStudentTeacherByStudentId = async (studentId) => {
  56 + return await request.get({ url: `/infra/student/student-teacher/get-by-student-id?studentId=` + studentId })
  57 +}
0 58 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/vue/StudentContactForm 0 → 100644
  1 +<template>
  2 + <el-form
  3 + ref="formRef"
  4 + :model="formData"
  5 + :rules="formRules"
  6 + v-loading="formLoading"
  7 + label-width="0px"
  8 + :inline-message="true"
  9 + >
  10 + <el-table :data="formData" class="-mt-10px">
  11 + <el-table-column label="序号" type="index" width="100" />
  12 + <el-table-column label="名字" min-width="150">
  13 + <template #default="{ row, $index }">
  14 + <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!">
  15 + <el-input v-model="row.name" placeholder="请输入名字" />
  16 + </el-form-item>
  17 + </template>
  18 + </el-table-column>
  19 + <el-table-column label="简介" min-width="200">
  20 + <template #default="{ row, $index }">
  21 + <el-form-item :prop="`${$index}.description`" :rules="formRules.description" class="mb-0px!">
  22 + <el-input v-model="row.description" type="textarea" placeholder="请输入简介" />
  23 + </el-form-item>
  24 + </template>
  25 + </el-table-column>
  26 + <el-table-column label="出生日期" min-width="150">
  27 + <template #default="{ row, $index }">
  28 + <el-form-item :prop="`${$index}.birthday`" :rules="formRules.birthday" class="mb-0px!">
  29 + <el-date-picker
  30 + v-model="row.birthday"
  31 + type="date"
  32 + value-format="x"
  33 + placeholder="选择出生日期"
  34 + />
  35 + </el-form-item>
  36 + </template>
  37 + </el-table-column>
  38 + <el-table-column label="性别" min-width="150">
  39 + <template #default="{ row, $index }">
  40 + <el-form-item :prop="`${$index}.sex`" :rules="formRules.sex" class="mb-0px!">
  41 + <el-select v-model="row.sex" placeholder="请选择性别">
  42 + <el-option
  43 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  44 + :key="dict.value"
  45 + :label="dict.label"
  46 + :value="dict.value"
  47 + />
  48 + </el-select>
  49 + </el-form-item>
  50 + </template>
  51 + </el-table-column>
  52 + <el-table-column label="是否有效" min-width="150">
  53 + <template #default="{ row, $index }">
  54 + <el-form-item :prop="`${$index}.enabled`" :rules="formRules.enabled" class="mb-0px!">
  55 + <el-radio-group v-model="row.enabled">
  56 + <el-radio
  57 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  58 + :key="dict.value"
  59 + :label="dict.value"
  60 + >
  61 + {{ dict.label }}
  62 + </el-radio>
  63 + </el-radio-group>
  64 + </el-form-item>
  65 + </template>
  66 + </el-table-column>
  67 + <el-table-column label="头像" min-width="200">
  68 + <template #default="{ row, $index }">
  69 + <el-form-item :prop="`${$index}.avatar`" :rules="formRules.avatar" class="mb-0px!">
  70 + <UploadImg v-model="row.avatar" />
  71 + </el-form-item>
  72 + </template>
  73 + </el-table-column>
  74 + <el-table-column label="附件" min-width="200">
  75 + <template #default="{ row, $index }">
  76 + <el-form-item :prop="`${$index}.video`" :rules="formRules.video" class="mb-0px!">
  77 + <UploadFile v-model="row.video" />
  78 + </el-form-item>
  79 + </template>
  80 + </el-table-column>
  81 + <el-table-column label="备注" min-width="400">
  82 + <template #default="{ row, $index }">
  83 + <el-form-item :prop="`${$index}.memo`" :rules="formRules.memo" class="mb-0px!">
  84 + <Editor v-model="row.memo" height="150px" />
  85 + </el-form-item>
  86 + </template>
  87 + </el-table-column>
  88 + <el-table-column align="center" fixed="right" label="操作" width="60">
  89 + <template #default="{ $index }">
  90 + <el-button @click="handleDelete($index)" link>—</el-button>
  91 + </template>
  92 + </el-table-column>
  93 + </el-table>
  94 + </el-form>
  95 + <el-row justify="center" class="mt-3">
  96 + <el-button @click="handleAdd" round>+ 添加学生联系人</el-button>
  97 + </el-row>
  98 +</template>
  99 +<script setup lang="ts">
  100 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  101 +import * as StudentApi from '@/api/infra/demo'
  102 +
  103 +const props = defineProps<{
  104 + studentId: undefined // 学生编号(主表的关联字段)
  105 +}>()
  106 +const formLoading = ref(false) // 表单的加载中
  107 +const formData = ref([])
  108 +const formRules = reactive({
  109 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  110 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  111 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  112 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  113 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  114 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  115 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  116 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  117 +})
  118 +const formRef = ref() // 表单 Ref
  119 +
  120 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  121 +watch(
  122 + () => props.studentId,
  123 + async (val) => {
  124 + // 1. 重置表单
  125 + formData.value = []
  126 + // 2. val 非空,则加载数据
  127 + if (!val) {
  128 + return;
  129 + }
  130 + try {
  131 + formLoading.value = true
  132 + formData.value = await StudentApi.getStudentContactListByStudentId(val)
  133 + } finally {
  134 + formLoading.value = false
  135 + }
  136 + },
  137 + { immediate: true }
  138 +)
  139 +
  140 +/** 新增按钮操作 */
  141 +const handleAdd = () => {
  142 + const row = {
  143 + id: undefined,
  144 + studentId: undefined,
  145 + name: undefined,
  146 + description: undefined,
  147 + birthday: undefined,
  148 + sex: undefined,
  149 + enabled: undefined,
  150 + avatar: undefined,
  151 + video: undefined,
  152 + memo: undefined
  153 + }
  154 + row.studentId = props.studentId
  155 + formData.value.push(row)
  156 +}
  157 +
  158 +/** 删除按钮操作 */
  159 +const handleDelete = (index) => {
  160 + formData.value.splice(index, 1)
  161 +}
  162 +
  163 +/** 表单校验 */
  164 +const validate = () => {
  165 + return formRef.value.validate()
  166 +}
  167 +
  168 +/** 表单值 */
  169 +const getData = () => {
  170 + return formData.value
  171 +}
  172 +
  173 +defineExpose({ validate, getData })
  174 +</script>
0 175 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/vue/StudentForm 0 → 100644
  1 +<template>
  2 + <Dialog :title="dialogTitle" v-model="dialogVisible">
  3 + <el-form
  4 + ref="formRef"
  5 + :model="formData"
  6 + :rules="formRules"
  7 + label-width="100px"
  8 + v-loading="formLoading"
  9 + >
  10 + <el-form-item label="名字" prop="name">
  11 + <el-input v-model="formData.name" placeholder="请输入名字" />
  12 + </el-form-item>
  13 + <el-form-item label="简介" prop="description">
  14 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  15 + </el-form-item>
  16 + <el-form-item label="出生日期" prop="birthday">
  17 + <el-date-picker
  18 + v-model="formData.birthday"
  19 + type="date"
  20 + value-format="x"
  21 + placeholder="选择出生日期"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item label="性别" prop="sex">
  25 + <el-select v-model="formData.sex" placeholder="请选择性别">
  26 + <el-option
  27 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  28 + :key="dict.value"
  29 + :label="dict.label"
  30 + :value="dict.value"
  31 + />
  32 + </el-select>
  33 + </el-form-item>
  34 + <el-form-item label="是否有效" prop="enabled">
  35 + <el-radio-group v-model="formData.enabled">
  36 + <el-radio
  37 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  38 + :key="dict.value"
  39 + :label="dict.value"
  40 + >
  41 + {{ dict.label }}
  42 + </el-radio>
  43 + </el-radio-group>
  44 + </el-form-item>
  45 + <el-form-item label="头像" prop="avatar">
  46 + <UploadImg v-model="formData.avatar" />
  47 + </el-form-item>
  48 + <el-form-item label="附件" prop="video">
  49 + <UploadFile v-model="formData.video" />
  50 + </el-form-item>
  51 + <el-form-item label="备注" prop="memo">
  52 + <Editor v-model="formData.memo" height="150px" />
  53 + </el-form-item>
  54 + </el-form>
  55 + <!-- 子表的表单 -->
  56 + <el-tabs v-model="subTabsName">
  57 + <el-tab-pane label="学生联系人" name="studentContact">
  58 + <StudentContactForm ref="studentContactFormRef" :student-id="formData.id" />
  59 + </el-tab-pane>
  60 + <el-tab-pane label="学生班主任" name="studentTeacher">
  61 + <StudentTeacherForm ref="studentTeacherFormRef" :student-id="formData.id" />
  62 + </el-tab-pane>
  63 + </el-tabs>
  64 + <template #footer>
  65 + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  66 + <el-button @click="dialogVisible = false">取 消</el-button>
  67 + </template>
  68 + </Dialog>
  69 +</template>
  70 +<script setup lang="ts">
  71 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  72 +import * as StudentApi from '@/api/infra/demo'
  73 +import StudentContactForm from './components/StudentContactForm.vue'
  74 +import StudentTeacherForm from './components/StudentTeacherForm.vue'
  75 +
  76 +const { t } = useI18n() // 国际化
  77 +const message = useMessage() // 消息弹窗
  78 +
  79 +const dialogVisible = ref(false) // 弹窗的是否展示
  80 +const dialogTitle = ref('') // 弹窗的标题
  81 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  82 +const formType = ref('') // 表单的类型:create - 新增;update - 修改
  83 +const formData = ref({
  84 + id: undefined,
  85 + name: undefined,
  86 + description: undefined,
  87 + birthday: undefined,
  88 + sex: undefined,
  89 + enabled: undefined,
  90 + avatar: undefined,
  91 + video: undefined,
  92 + memo: undefined
  93 +})
  94 +const formRules = reactive({
  95 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  96 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  97 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  98 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  99 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  100 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  101 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  102 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  103 +})
  104 +const formRef = ref() // 表单 Ref
  105 +
  106 +/** 子表的表单 */
  107 +const subTabsName = ref('studentContact')
  108 +const studentContactFormRef = ref()
  109 +const studentTeacherFormRef = ref()
  110 +
  111 +/** 打开弹窗 */
  112 +const open = async (type: string, id?: number) => {
  113 + dialogVisible.value = true
  114 + dialogTitle.value = t('action.' + type)
  115 + formType.value = type
  116 + resetForm()
  117 + // 修改时,设置数据
  118 + if (id) {
  119 + formLoading.value = true
  120 + try {
  121 + formData.value = await StudentApi.getStudent(id)
  122 + } finally {
  123 + formLoading.value = false
  124 + }
  125 + }
  126 +}
  127 +defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  128 +
  129 +/** 提交表单 */
  130 +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  131 +const submitForm = async () => {
  132 + // 校验表单
  133 + await formRef.value.validate()
  134 + // 校验子表单
  135 + try {
  136 + await studentContactFormRef.value.validate()
  137 + } catch (e) {
  138 + subTabsName.value = 'studentContact'
  139 + return
  140 + }
  141 + try {
  142 + await studentTeacherFormRef.value.validate()
  143 + } catch (e) {
  144 + subTabsName.value = 'studentTeacher'
  145 + return
  146 + }
  147 + // 提交请求
  148 + formLoading.value = true
  149 + try {
  150 + const data = formData.value as unknown as StudentApi.StudentVO
  151 + // 拼接子表的数据
  152 + data.studentContacts = studentContactFormRef.value.getData()
  153 + data.studentTeacher = studentTeacherFormRef.value.getData()
  154 + if (formType.value === 'create') {
  155 + await StudentApi.createStudent(data)
  156 + message.success(t('common.createSuccess'))
  157 + } else {
  158 + await StudentApi.updateStudent(data)
  159 + message.success(t('common.updateSuccess'))
  160 + }
  161 + dialogVisible.value = false
  162 + // 发送操作成功的事件
  163 + emit('success')
  164 + } finally {
  165 + formLoading.value = false
  166 + }
  167 +}
  168 +
  169 +/** 重置表单 */
  170 +const resetForm = () => {
  171 + formData.value = {
  172 + id: undefined,
  173 + name: undefined,
  174 + description: undefined,
  175 + birthday: undefined,
  176 + sex: undefined,
  177 + enabled: undefined,
  178 + avatar: undefined,
  179 + video: undefined,
  180 + memo: undefined
  181 + }
  182 + formRef.value?.resetFields()
  183 +}
  184 +</script>
0 185 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/vue/StudentTeacherForm 0 → 100644
  1 +<template>
  2 + <el-form
  3 + ref="formRef"
  4 + :model="formData"
  5 + :rules="formRules"
  6 + label-width="100px"
  7 + v-loading="formLoading"
  8 + >
  9 + <el-form-item label="名字" prop="name">
  10 + <el-input v-model="formData.name" placeholder="请输入名字" />
  11 + </el-form-item>
  12 + <el-form-item label="简介" prop="description">
  13 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  14 + </el-form-item>
  15 + <el-form-item label="出生日期" prop="birthday">
  16 + <el-date-picker
  17 + v-model="formData.birthday"
  18 + type="date"
  19 + value-format="x"
  20 + placeholder="选择出生日期"
  21 + />
  22 + </el-form-item>
  23 + <el-form-item label="性别" prop="sex">
  24 + <el-select v-model="formData.sex" placeholder="请选择性别">
  25 + <el-option
  26 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  27 + :key="dict.value"
  28 + :label="dict.label"
  29 + :value="dict.value"
  30 + />
  31 + </el-select>
  32 + </el-form-item>
  33 + <el-form-item label="是否有效" prop="enabled">
  34 + <el-radio-group v-model="formData.enabled">
  35 + <el-radio
  36 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  37 + :key="dict.value"
  38 + :label="dict.value"
  39 + >
  40 + {{ dict.label }}
  41 + </el-radio>
  42 + </el-radio-group>
  43 + </el-form-item>
  44 + <el-form-item label="头像" prop="avatar">
  45 + <UploadImg v-model="formData.avatar" />
  46 + </el-form-item>
  47 + <el-form-item label="附件" prop="video">
  48 + <UploadFile v-model="formData.video" />
  49 + </el-form-item>
  50 + <el-form-item label="备注" prop="memo">
  51 + <Editor v-model="formData.memo" height="150px" />
  52 + </el-form-item>
  53 + </el-form>
  54 +</template>
  55 +<script setup lang="ts">
  56 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  57 +import * as StudentApi from '@/api/infra/demo'
  58 +
  59 +const props = defineProps<{
  60 + studentId: undefined // 学生编号(主表的关联字段)
  61 +}>()
  62 +const formLoading = ref(false) // 表单的加载中
  63 +const formData = ref([])
  64 +const formRules = reactive({
  65 + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }],
  66 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  67 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  68 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  69 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  70 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  71 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  72 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  73 +})
  74 +const formRef = ref() // 表单 Ref
  75 +
  76 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  77 +watch(
  78 + () => props.studentId,
  79 + async (val) => {
  80 + // 1. 重置表单
  81 + formData.value = {
  82 + id: undefined,
  83 + studentId: undefined,
  84 + name: undefined,
  85 + description: undefined,
  86 + birthday: undefined,
  87 + sex: undefined,
  88 + enabled: undefined,
  89 + avatar: undefined,
  90 + video: undefined,
  91 + memo: undefined,
  92 + }
  93 + // 2. val 非空,则加载数据
  94 + if (!val) {
  95 + return;
  96 + }
  97 + try {
  98 + formLoading.value = true
  99 + const data = await StudentApi.getStudentTeacherByStudentId(val)
  100 + if (!data) {
  101 + return
  102 + }
  103 + formData.value = data
  104 + } finally {
  105 + formLoading.value = false
  106 + }
  107 + },
  108 + { immediate: true }
  109 +)
  110 +
  111 +/** 表单校验 */
  112 +const validate = () => {
  113 + return formRef.value.validate()
  114 +}
  115 +
  116 +/** 表单值 */
  117 +const getData = () => {
  118 + return formData.value
  119 +}
  120 +
  121 +defineExpose({ validate, getData })
  122 +</script>
0 123 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/vue/index 0 → 100644
  1 +<template>
  2 + <ContentWrap>
  3 + <!-- 搜索工作栏 -->
  4 + <el-form
  5 + class="-mb-15px"
  6 + :model="queryParams"
  7 + ref="queryFormRef"
  8 + :inline="true"
  9 + label-width="68px"
  10 + >
  11 + <el-form-item label="名字" prop="name">
  12 + <el-input
  13 + v-model="queryParams.name"
  14 + placeholder="请输入名字"
  15 + clearable
  16 + @keyup.enter="handleQuery"
  17 + class="!w-240px"
  18 + />
  19 + </el-form-item>
  20 + <el-form-item label="出生日期" prop="birthday">
  21 + <el-date-picker
  22 + v-model="queryParams.birthday"
  23 + value-format="YYYY-MM-DD"
  24 + type="date"
  25 + placeholder="选择出生日期"
  26 + clearable
  27 + class="!w-240px"
  28 + />
  29 + </el-form-item>
  30 + <el-form-item label="性别" prop="sex">
  31 + <el-select
  32 + v-model="queryParams.sex"
  33 + placeholder="请选择性别"
  34 + clearable
  35 + class="!w-240px"
  36 + >
  37 + <el-option
  38 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  39 + :key="dict.value"
  40 + :label="dict.label"
  41 + :value="dict.value"
  42 + />
  43 + </el-select>
  44 + </el-form-item>
  45 + <el-form-item label="是否有效" prop="enabled">
  46 + <el-select
  47 + v-model="queryParams.enabled"
  48 + placeholder="请选择是否有效"
  49 + clearable
  50 + class="!w-240px"
  51 + >
  52 + <el-option
  53 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  54 + :key="dict.value"
  55 + :label="dict.label"
  56 + :value="dict.value"
  57 + />
  58 + </el-select>
  59 + </el-form-item>
  60 + <el-form-item label="创建时间" prop="createTime">
  61 + <el-date-picker
  62 + v-model="queryParams.createTime"
  63 + value-format="YYYY-MM-DD HH:mm:ss"
  64 + type="daterange"
  65 + start-placeholder="开始日期"
  66 + end-placeholder="结束日期"
  67 + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  68 + class="!w-240px"
  69 + />
  70 + </el-form-item>
  71 + <el-form-item>
  72 + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
  73 + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
  74 + <el-button
  75 + type="primary"
  76 + plain
  77 + @click="openForm('create')"
  78 + v-hasPermi="['infra:student:create']"
  79 + >
  80 + <Icon icon="ep:plus" class="mr-5px" /> 新增
  81 + </el-button>
  82 + <el-button
  83 + type="success"
  84 + plain
  85 + @click="handleExport"
  86 + :loading="exportLoading"
  87 + v-hasPermi="['infra:student:export']"
  88 + >
  89 + <Icon icon="ep:download" class="mr-5px" /> 导出
  90 + </el-button>
  91 + </el-form-item>
  92 + </el-form>
  93 + </ContentWrap>
  94 +
  95 + <!-- 列表 -->
  96 + <ContentWrap>
  97 + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  98 + <el-table-column label="编号" align="center" prop="id" />
  99 + <el-table-column label="名字" align="center" prop="name" />
  100 + <el-table-column label="简介" align="center" prop="description" />
  101 + <el-table-column
  102 + label="出生日期"
  103 + align="center"
  104 + prop="birthday"
  105 + :formatter="dateFormatter"
  106 + width="180px"
  107 + />
  108 + <el-table-column label="性别" align="center" prop="sex">
  109 + <template #default="scope">
  110 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  111 + </template>
  112 + </el-table-column>
  113 + <el-table-column label="是否有效" align="center" prop="enabled">
  114 + <template #default="scope">
  115 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  116 + </template>
  117 + </el-table-column>
  118 + <el-table-column label="头像" align="center" prop="avatar" />
  119 + <el-table-column label="附件" align="center" prop="video" />
  120 + <el-table-column label="备注" align="center" prop="memo" />
  121 + <el-table-column
  122 + label="创建时间"
  123 + align="center"
  124 + prop="createTime"
  125 + :formatter="dateFormatter"
  126 + width="180px"
  127 + />
  128 + <el-table-column label="操作" align="center">
  129 + <template #default="scope">
  130 + <el-button
  131 + link
  132 + type="primary"
  133 + @click="openForm('update', scope.row.id)"
  134 + v-hasPermi="['infra:student:update']"
  135 + >
  136 + 编辑
  137 + </el-button>
  138 + <el-button
  139 + link
  140 + type="danger"
  141 + @click="handleDelete(scope.row.id)"
  142 + v-hasPermi="['infra:student:delete']"
  143 + >
  144 + 删除
  145 + </el-button>
  146 + </template>
  147 + </el-table-column>
  148 + </el-table>
  149 + <!-- 分页 -->
  150 + <Pagination
  151 + :total="total"
  152 + v-model:page="queryParams.pageNo"
  153 + v-model:limit="queryParams.pageSize"
  154 + @pagination="getList"
  155 + />
  156 + </ContentWrap>
  157 +
  158 + <!-- 表单弹窗:添加/修改 -->
  159 + <StudentForm ref="formRef" @success="getList" />
  160 +</template>
  161 +
  162 +<script setup lang="ts">
  163 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  164 +import { dateFormatter } from '@/utils/formatTime'
  165 +import download from '@/utils/download'
  166 +import * as StudentApi from '@/api/infra/demo'
  167 +import StudentForm from './StudentForm.vue'
  168 +
  169 +defineOptions({ name: 'InfraStudent' })
  170 +
  171 +const message = useMessage() // 消息弹窗
  172 +const { t } = useI18n() // 国际化
  173 +
  174 +const loading = ref(true) // 列表的加载中
  175 +const list = ref([]) // 列表的数据
  176 +const total = ref(0) // 列表的总页数
  177 +const queryParams = reactive({
  178 + pageNo: 1,
  179 + pageSize: 10,
  180 + name: null,
  181 + birthday: null,
  182 + birthday: [],
  183 + sex: null,
  184 + enabled: null,
  185 + createTime: []
  186 +})
  187 +const queryFormRef = ref() // 搜索的表单
  188 +const exportLoading = ref(false) // 导出的加载中
  189 +
  190 +/** 查询列表 */
  191 +const getList = async () => {
  192 + loading.value = true
  193 + try {
  194 + const data = await StudentApi.getStudentPage(queryParams)
  195 + list.value = data.list
  196 + total.value = data.total
  197 + } finally {
  198 + loading.value = false
  199 + }
  200 +}
  201 +
  202 +/** 搜索按钮操作 */
  203 +const handleQuery = () => {
  204 + queryParams.pageNo = 1
  205 + getList()
  206 +}
  207 +
  208 +/** 重置按钮操作 */
  209 +const resetQuery = () => {
  210 + queryFormRef.value.resetFields()
  211 + handleQuery()
  212 +}
  213 +
  214 +/** 添加/修改操作 */
  215 +const formRef = ref()
  216 +const openForm = (type: string, id?: number) => {
  217 + formRef.value.open(type, id)
  218 +}
  219 +
  220 +/** 删除按钮操作 */
  221 +const handleDelete = async (id: number) => {
  222 + try {
  223 + // 删除的二次确认
  224 + await message.delConfirm()
  225 + // 发起删除
  226 + await StudentApi.deleteStudent(id)
  227 + message.success(t('common.delSuccess'))
  228 + // 刷新列表
  229 + await getList()
  230 + } catch {}
  231 +}
  232 +
  233 +/** 导出按钮操作 */
  234 +const handleExport = async () => {
  235 + try {
  236 + // 导出的二次确认
  237 + await message.exportConfirm()
  238 + // 发起导出
  239 + exportLoading.value = true
  240 + const data = await StudentApi.exportStudent(queryParams)
  241 + download.excel(data, '学生.xls')
  242 + } catch {
  243 + } finally {
  244 + exportLoading.value = false
  245 + }
  246 +}
  247 +
  248 +/** 初始化 **/
  249 +onMounted(() => {
  250 + getList()
  251 +})
  252 +</script>
0 253 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_master_normal/xml/InfraStudentMapper 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraStudentPageReqVO",
  3 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentPageReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraStudentRespVO",
  6 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraStudentSaveReqVO",
  9 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraStudentSaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraStudentController",
  12 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraStudentController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraStudentDO",
  15 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraStudentDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraStudentMapper",
  18 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraStudentMapper.java"
  19 +}, {
  20 + "contentPath" : "xml/InfraStudentMapper",
  21 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraStudentMapper.xml"
  22 +}, {
  23 + "contentPath" : "java/InfraStudentServiceImpl",
  24 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImpl.java"
  25 +}, {
  26 + "contentPath" : "java/InfraStudentService",
  27 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentService.java"
  28 +}, {
  29 + "contentPath" : "java/InfraStudentServiceImplTest",
  30 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraStudentServiceImplTest.java"
  31 +}, {
  32 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  33 + "filePath" : "yudao-module-infra/yudao-module-infra-api/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-vue3/src/views/infra/demo/index.vue"
  43 +}, {
  44 + "contentPath" : "vue/StudentForm",
  45 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/StudentForm.vue"
  46 +}, {
  47 + "contentPath" : "ts/index",
  48 + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts"
  49 +} ]
0 50 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/ErrorCodeConstants_手动操作 0 → 100644
  1 +// TODO 待办:请将下面的错误码复制到 yudao-module-infra-api 模块的 ErrorCodeConstants 类中。注意,请给“TODO 补充编号”设置一个错误码编号!!!
  2 +// ========== 学生 TODO 补充编号 ==========
  3 +ErrorCode STUDENT_NOT_EXISTS = new ErrorCode(TODO 补充编号, "学生不存在");
0 4 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.security.access.prepost.PreAuthorize;
  7 +import io.swagger.v3.oas.annotations.tags.Tag;
  8 +import io.swagger.v3.oas.annotations.Parameter;
  9 +import io.swagger.v3.oas.annotations.Operation;
  10 +
  11 +import javax.validation.constraints.*;
  12 +import javax.validation.*;
  13 +import javax.servlet.http.*;
  14 +import java.util.*;
  15 +import java.io.IOException;
  16 +
  17 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  18 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  19 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  20 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  24 +
  25 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  26 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  27 +
  28 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  29 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  30 +import cn.iocoder.yudao.module.infra.service.demo.InfraStudentService;
  31 +
  32 +@Tag(name = "管理后台 - 学生")
  33 +@RestController
  34 +@RequestMapping("/infra/student")
  35 +@Validated
  36 +public class InfraStudentController {
  37 +
  38 + @Resource
  39 + private InfraStudentService studentService;
  40 +
  41 + @PostMapping("/create")
  42 + @Operation(summary = "创建学生")
  43 + @PreAuthorize("@ss.hasPermission('infra:student:create')")
  44 + public CommonResult<Long> createStudent(@Valid @RequestBody InfraStudentSaveReqVO createReqVO) {
  45 + return success(studentService.createStudent(createReqVO));
  46 + }
  47 +
  48 + @PutMapping("/update")
  49 + @Operation(summary = "更新学生")
  50 + @PreAuthorize("@ss.hasPermission('infra:student:update')")
  51 + public CommonResult<Boolean> updateStudent(@Valid @RequestBody InfraStudentSaveReqVO updateReqVO) {
  52 + studentService.updateStudent(updateReqVO);
  53 + return success(true);
  54 + }
  55 +
  56 + @DeleteMapping("/delete")
  57 + @Operation(summary = "删除学生")
  58 + @Parameter(name = "id", description = "编号", required = true)
  59 + @PreAuthorize("@ss.hasPermission('infra:student:delete')")
  60 + public CommonResult<Boolean> deleteStudent(@RequestParam("id") Long id) {
  61 + studentService.deleteStudent(id);
  62 + return success(true);
  63 + }
  64 +
  65 + @GetMapping("/get")
  66 + @Operation(summary = "获得学生")
  67 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  68 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  69 + public CommonResult<InfraStudentRespVO> getStudent(@RequestParam("id") Long id) {
  70 + InfraStudentDO student = studentService.getStudent(id);
  71 + return success(BeanUtils.toBean(student, InfraStudentRespVO.class));
  72 + }
  73 +
  74 + @GetMapping("/page")
  75 + @Operation(summary = "获得学生分页")
  76 + @PreAuthorize("@ss.hasPermission('infra:student:query')")
  77 + public CommonResult<PageResult<InfraStudentRespVO>> getStudentPage(@Valid InfraStudentPageReqVO pageReqVO) {
  78 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(pageReqVO);
  79 + return success(BeanUtils.toBean(pageResult, InfraStudentRespVO.class));
  80 + }
  81 +
  82 + @GetMapping("/export-excel")
  83 + @Operation(summary = "导出学生 Excel")
  84 + @PreAuthorize("@ss.hasPermission('infra:student:export')")
  85 + @OperateLog(type = EXPORT)
  86 + public void exportStudentExcel(@Valid InfraStudentPageReqVO pageReqVO,
  87 + HttpServletResponse response) throws IOException {
  88 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  89 + List<InfraStudentDO> list = studentService.getStudentPage(pageReqVO).getList();
  90 + // 导出 Excel
  91 + ExcelUtils.write(response, "学生.xls", "数据", InfraStudentRespVO.class,
  92 + BeanUtils.toBean(list, InfraStudentRespVO.class));
  93 + }
  94 +
  95 +}
0 96 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import java.time.LocalDateTime;
  6 +import java.time.LocalDateTime;
  7 +import com.baomidou.mybatisplus.annotation.*;
  8 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  9 +
  10 +/**
  11 + * 学生 DO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@TableName("infra_student")
  16 +@KeySequence("infra_student_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  17 +@Data
  18 +@EqualsAndHashCode(callSuper = true)
  19 +@ToString(callSuper = true)
  20 +@Builder
  21 +@NoArgsConstructor
  22 +@AllArgsConstructor
  23 +public class InfraStudentDO extends BaseDO {
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 简介
  36 + */
  37 + private String description;
  38 + /**
  39 + * 出生日期
  40 + */
  41 + private LocalDateTime birthday;
  42 + /**
  43 + * 性别
  44 + *
  45 + * 枚举 {@link TODO system_user_sex 对应的类}
  46 + */
  47 + private Integer sex;
  48 + /**
  49 + * 是否有效
  50 + *
  51 + * 枚举 {@link TODO infra_boolean_string 对应的类}
  52 + */
  53 + private Boolean enabled;
  54 + /**
  55 + * 头像
  56 + */
  57 + private String avatar;
  58 + /**
  59 + * 附件
  60 + */
  61 + private String video;
  62 + /**
  63 + * 备注
  64 + */
  65 + private String memo;
  66 +
  67 +}
0 68 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 学生 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraStudentMapper extends BaseMapperX<InfraStudentDO> {
  19 +
  20 + default PageResult<InfraStudentDO> selectPage(InfraStudentPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<InfraStudentDO>()
  22 + .likeIfPresent(InfraStudentDO::getName, reqVO.getName())
  23 + .eqIfPresent(InfraStudentDO::getBirthday, reqVO.getBirthday())
  24 + .eqIfPresent(InfraStudentDO::getSex, reqVO.getSex())
  25 + .eqIfPresent(InfraStudentDO::getEnabled, reqVO.getEnabled())
  26 + .betweenIfPresent(InfraStudentDO::getCreateTime, reqVO.getCreateTime())
  27 + .orderByDesc(InfraStudentDO::getId));
  28 + }
  29 +
  30 +}
0 31 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentPageReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@Schema(description = "管理后台 - 学生分页 Request VO")
  13 +@Data
  14 +@EqualsAndHashCode(callSuper = true)
  15 +@ToString(callSuper = true)
  16 +public class InfraStudentPageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "名字", example = "芋头")
  19 + private String name;
  20 +
  21 + @Schema(description = "出生日期")
  22 + private LocalDateTime birthday;
  23 +
  24 + @Schema(description = "性别", example = "1")
  25 + private Integer sex;
  26 +
  27 + @Schema(description = "是否有效", example = "true")
  28 + private Boolean enabled;
  29 +
  30 + @Schema(description = "创建时间")
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + private LocalDateTime[] createTime;
  33 +
  34 +}
0 35 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import java.util.*;
  7 +import org.springframework.format.annotation.DateTimeFormat;
  8 +import java.time.LocalDateTime;
  9 +import com.alibaba.excel.annotation.*;
  10 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  11 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  12 +
  13 +@Schema(description = "管理后台 - 学生 Response VO")
  14 +@Data
  15 +@ExcelIgnoreUnannotated
  16 +public class InfraStudentRespVO {
  17 +
  18 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  19 + @ExcelProperty("编号")
  20 + private Long id;
  21 +
  22 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  23 + @ExcelProperty("名字")
  24 + private String name;
  25 +
  26 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  27 + @ExcelProperty("简介")
  28 + private String description;
  29 +
  30 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + @ExcelProperty("出生日期")
  32 + private LocalDateTime birthday;
  33 +
  34 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  35 + @ExcelProperty(value = "性别", converter = DictConvert.class)
  36 + @DictFormat("system_user_sex") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  37 + private Integer sex;
  38 +
  39 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  40 + @ExcelProperty(value = "是否有效", converter = DictConvert.class)
  41 + @DictFormat("infra_boolean_string") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
  42 + private Boolean enabled;
  43 +
  44 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  45 + @ExcelProperty("头像")
  46 + private String avatar;
  47 +
  48 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  49 + @ExcelProperty("附件")
  50 + private String video;
  51 +
  52 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  53 + @ExcelProperty("备注")
  54 + private String memo;
  55 +
  56 + @Schema(description = "创建时间")
  57 + @ExcelProperty("创建时间")
  58 + private LocalDateTime createTime;
  59 +
  60 +}
0 61 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentSaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import javax.validation.constraints.*;
  7 +import java.util.*;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +import java.time.LocalDateTime;
  10 +
  11 +@Schema(description = "管理后台 - 学生新增/修改 Request VO")
  12 +@Data
  13 +public class InfraStudentSaveReqVO {
  14 +
  15 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  16 + private Long id;
  17 +
  18 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  19 + @NotEmpty(message = "名字不能为空")
  20 + private String name;
  21 +
  22 + @Schema(description = "简介", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是介绍")
  23 + @NotEmpty(message = "简介不能为空")
  24 + private String description;
  25 +
  26 + @Schema(description = "出生日期", requiredMode = Schema.RequiredMode.REQUIRED)
  27 + @NotNull(message = "出生日期不能为空")
  28 + private LocalDateTime birthday;
  29 +
  30 + @Schema(description = "性别", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  31 + @NotNull(message = "性别不能为空")
  32 + private Integer sex;
  33 +
  34 + @Schema(description = "是否有效", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
  35 + @NotNull(message = "是否有效不能为空")
  36 + private Boolean enabled;
  37 +
  38 + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
  39 + @NotEmpty(message = "头像不能为空")
  40 + private String avatar;
  41 +
  42 + @Schema(description = "附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.mp4")
  43 + @NotEmpty(message = "附件不能为空")
  44 + private String video;
  45 +
  46 + @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是备注")
  47 + @NotEmpty(message = "备注不能为空")
  48 + private String memo;
  49 +
  50 +}
0 51 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import javax.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  9 +
  10 +/**
  11 + * 学生 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface InfraStudentService {
  16 +
  17 + /**
  18 + * 创建学生
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createStudent(@Valid InfraStudentSaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 更新学生
  27 + *
  28 + * @param updateReqVO 更新信息
  29 + */
  30 + void updateStudent(@Valid InfraStudentSaveReqVO updateReqVO);
  31 +
  32 + /**
  33 + * 删除学生
  34 + *
  35 + * @param id 编号
  36 + */
  37 + void deleteStudent(Long id);
  38 +
  39 + /**
  40 + * 获得学生
  41 + *
  42 + * @param id 编号
  43 + * @return 学生
  44 + */
  45 + InfraStudentDO getStudent(Long id);
  46 +
  47 + /**
  48 + * 获得学生分页
  49 + *
  50 + * @param pageReqVO 分页查询
  51 + * @return 学生分页
  52 + */
  53 + PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO);
  54 +
  55 +}
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.transaction.annotation.Transactional;
  7 +
  8 +import java.util.*;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  11 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  12 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  13 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  14 +
  15 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  16 +
  17 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  18 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  19 +
  20 +/**
  21 + * 学生 Service 实现类
  22 + *
  23 + * @author 芋道源码
  24 + */
  25 +@Service
  26 +@Validated
  27 +public class InfraStudentServiceImpl implements InfraStudentService {
  28 +
  29 + @Resource
  30 + private InfraStudentMapper studentMapper;
  31 +
  32 + @Override
  33 + public Long createStudent(InfraStudentSaveReqVO createReqVO) {
  34 + // 插入
  35 + InfraStudentDO student = BeanUtils.toBean(createReqVO, InfraStudentDO.class);
  36 + studentMapper.insert(student);
  37 + // 返回
  38 + return student.getId();
  39 + }
  40 +
  41 + @Override
  42 + public void updateStudent(InfraStudentSaveReqVO updateReqVO) {
  43 + // 校验存在
  44 + validateStudentExists(updateReqVO.getId());
  45 + // 更新
  46 + InfraStudentDO updateObj = BeanUtils.toBean(updateReqVO, InfraStudentDO.class);
  47 + studentMapper.updateById(updateObj);
  48 + }
  49 +
  50 + @Override
  51 + public void deleteStudent(Long id) {
  52 + // 校验存在
  53 + validateStudentExists(id);
  54 + // 删除
  55 + studentMapper.deleteById(id);
  56 + }
  57 +
  58 + private void validateStudentExists(Long id) {
  59 + if (studentMapper.selectById(id) == null) {
  60 + throw exception(STUDENT_NOT_EXISTS);
  61 + }
  62 + }
  63 +
  64 + @Override
  65 + public InfraStudentDO getStudent(Long id) {
  66 + return studentMapper.selectById(id);
  67 + }
  68 +
  69 + @Override
  70 + public PageResult<InfraStudentDO> getStudentPage(InfraStudentPageReqVO pageReqVO) {
  71 + return studentMapper.selectPage(pageReqVO);
  72 + }
  73 +
  74 +}
0 75 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/java/InfraStudentServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.boot.test.mock.mockito.MockBean;
  6 +
  7 +import javax.annotation.Resource;
  8 +
  9 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  10 +
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraStudentDO;
  13 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  15 +
  16 +import javax.annotation.Resource;
  17 +import org.springframework.context.annotation.Import;
  18 +import java.util.*;
  19 +import java.time.LocalDateTime;
  20 +
  21 +import static cn.hutool.core.util.RandomUtil.*;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  24 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  27 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  28 +import static org.junit.jupiter.api.Assertions.*;
  29 +import static org.mockito.Mockito.*;
  30 +
  31 +/**
  32 + * {@link InfraStudentServiceImpl} 的单元测试类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Import(InfraStudentServiceImpl.class)
  37 +public class InfraStudentServiceImplTest extends BaseDbUnitTest {
  38 +
  39 + @Resource
  40 + private InfraStudentServiceImpl studentService;
  41 +
  42 + @Resource
  43 + private InfraStudentMapper studentMapper;
  44 +
  45 + @Test
  46 + public void testCreateStudent_success() {
  47 + // 准备参数
  48 + InfraStudentSaveReqVO createReqVO = randomPojo(InfraStudentSaveReqVO.class).setId(null);
  49 +
  50 + // 调用
  51 + Long studentId = studentService.createStudent(createReqVO);
  52 + // 断言
  53 + assertNotNull(studentId);
  54 + // 校验记录的属性是否正确
  55 + InfraStudentDO student = studentMapper.selectById(studentId);
  56 + assertPojoEquals(createReqVO, student, "id");
  57 + }
  58 +
  59 + @Test
  60 + public void testUpdateStudent_success() {
  61 + // mock 数据
  62 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  63 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  64 + // 准备参数
  65 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class, o -> {
  66 + o.setId(dbStudent.getId()); // 设置更新的 ID
  67 + });
  68 +
  69 + // 调用
  70 + studentService.updateStudent(updateReqVO);
  71 + // 校验是否更新正确
  72 + InfraStudentDO student = studentMapper.selectById(updateReqVO.getId()); // 获取最新的
  73 + assertPojoEquals(updateReqVO, student);
  74 + }
  75 +
  76 + @Test
  77 + public void testUpdateStudent_notExists() {
  78 + // 准备参数
  79 + InfraStudentSaveReqVO updateReqVO = randomPojo(InfraStudentSaveReqVO.class);
  80 +
  81 + // 调用, 并断言异常
  82 + assertServiceException(() -> studentService.updateStudent(updateReqVO), STUDENT_NOT_EXISTS);
  83 + }
  84 +
  85 + @Test
  86 + public void testDeleteStudent_success() {
  87 + // mock 数据
  88 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class);
  89 + studentMapper.insert(dbStudent);// @Sql: 先插入出一条存在的数据
  90 + // 准备参数
  91 + Long id = dbStudent.getId();
  92 +
  93 + // 调用
  94 + studentService.deleteStudent(id);
  95 + // 校验数据不存在了
  96 + assertNull(studentMapper.selectById(id));
  97 + }
  98 +
  99 + @Test
  100 + public void testDeleteStudent_notExists() {
  101 + // 准备参数
  102 + Long id = randomLongId();
  103 +
  104 + // 调用, 并断言异常
  105 + assertServiceException(() -> studentService.deleteStudent(id), STUDENT_NOT_EXISTS);
  106 + }
  107 +
  108 + @Test
  109 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  110 + public void testGetStudentPage() {
  111 + // mock 数据
  112 + InfraStudentDO dbStudent = randomPojo(InfraStudentDO.class, o -> { // 等会查询到
  113 + o.setName(null);
  114 + o.setBirthday(null);
  115 + o.setSex(null);
  116 + o.setEnabled(null);
  117 + o.setCreateTime(null);
  118 + });
  119 + studentMapper.insert(dbStudent);
  120 + // 测试 name 不匹配
  121 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setName(null)));
  122 + // 测试 birthday 不匹配
  123 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setBirthday(null)));
  124 + // 测试 sex 不匹配
  125 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setSex(null)));
  126 + // 测试 enabled 不匹配
  127 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setEnabled(null)));
  128 + // 测试 createTime 不匹配
  129 + studentMapper.insert(cloneIgnoreId(dbStudent, o -> o.setCreateTime(null)));
  130 + // 准备参数
  131 + InfraStudentPageReqVO reqVO = new InfraStudentPageReqVO();
  132 + reqVO.setName(null);
  133 + reqVO.setBirthday(null);
  134 + reqVO.setSex(null);
  135 + reqVO.setEnabled(null);
  136 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  137 +
  138 + // 调用
  139 + PageResult<InfraStudentDO> pageResult = studentService.getStudentPage(reqVO);
  140 + // 断言
  141 + assertEquals(1, pageResult.getTotal());
  142 + assertEquals(1, pageResult.getList().size());
  143 + assertPojoEquals(dbStudent, pageResult.getList().get(0));
  144 + }
  145 +
  146 +}
0 147 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_student" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" varchar NOT NULL,
  6 + "birthday" varchar NOT NULL,
  7 + "sex" int NOT NULL,
  8 + "enabled" bit NOT NULL,
  9 + "avatar" varchar NOT NULL,
  10 + "video" varchar NOT NULL,
  11 + "memo" varchar NOT NULL,
  12 + "create_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + PRIMARY KEY ("id")
  14 +) COMMENT '学生表';
  15 +
  16 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  17 +DELETE FROM "infra_student";
0 18 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '学生管理', '', 2, 0, 888,
  8 + 'student', '', 'infra/demo/index', 0, 'InfraStudent'
  9 +);
  10 +
  11 +-- 按钮父菜单ID
  12 +-- 暂时只支持 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 +);
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/ts/index 0 → 100644
  1 +import request from '@/config/axios'
  2 +
  3 +export interface StudentVO {
  4 + id: number
  5 + name: string
  6 + description: string
  7 + birthday: Date
  8 + sex: number
  9 + enabled: boolean
  10 + avatar: string
  11 + video: string
  12 + memo: string
  13 +}
  14 +
  15 +// 查询学生分页
  16 +export const getStudentPage = async (params) => {
  17 + return await request.get({ url: `/infra/student/page`, params })
  18 +}
  19 +
  20 +// 查询学生详情
  21 +export const getStudent = async (id: number) => {
  22 + return await request.get({ url: `/infra/student/get?id=` + id })
  23 +}
  24 +
  25 +// 新增学生
  26 +export const createStudent = async (data: StudentVO) => {
  27 + return await request.post({ url: `/infra/student/create`, data })
  28 +}
  29 +
  30 +// 修改学生
  31 +export const updateStudent = async (data: StudentVO) => {
  32 + return await request.put({ url: `/infra/student/update`, data })
  33 +}
  34 +
  35 +// 删除学生
  36 +export const deleteStudent = async (id: number) => {
  37 + return await request.delete({ url: `/infra/student/delete?id=` + id })
  38 +}
  39 +
  40 +// 导出学生 Excel
  41 +export const exportStudent = async (params) => {
  42 + return await request.download({ url: `/infra/student/export-excel`, params })
  43 +}
0 44 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/vue/StudentForm 0 → 100644
  1 +<template>
  2 + <Dialog :title="dialogTitle" v-model="dialogVisible">
  3 + <el-form
  4 + ref="formRef"
  5 + :model="formData"
  6 + :rules="formRules"
  7 + label-width="100px"
  8 + v-loading="formLoading"
  9 + >
  10 + <el-form-item label="名字" prop="name">
  11 + <el-input v-model="formData.name" placeholder="请输入名字" />
  12 + </el-form-item>
  13 + <el-form-item label="简介" prop="description">
  14 + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" />
  15 + </el-form-item>
  16 + <el-form-item label="出生日期" prop="birthday">
  17 + <el-date-picker
  18 + v-model="formData.birthday"
  19 + type="date"
  20 + value-format="x"
  21 + placeholder="选择出生日期"
  22 + />
  23 + </el-form-item>
  24 + <el-form-item label="性别" prop="sex">
  25 + <el-select v-model="formData.sex" placeholder="请选择性别">
  26 + <el-option
  27 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  28 + :key="dict.value"
  29 + :label="dict.label"
  30 + :value="dict.value"
  31 + />
  32 + </el-select>
  33 + </el-form-item>
  34 + <el-form-item label="是否有效" prop="enabled">
  35 + <el-radio-group v-model="formData.enabled">
  36 + <el-radio
  37 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  38 + :key="dict.value"
  39 + :label="dict.value"
  40 + >
  41 + {{ dict.label }}
  42 + </el-radio>
  43 + </el-radio-group>
  44 + </el-form-item>
  45 + <el-form-item label="头像" prop="avatar">
  46 + <UploadImg v-model="formData.avatar" />
  47 + </el-form-item>
  48 + <el-form-item label="附件" prop="video">
  49 + <UploadFile v-model="formData.video" />
  50 + </el-form-item>
  51 + <el-form-item label="备注" prop="memo">
  52 + <Editor v-model="formData.memo" height="150px" />
  53 + </el-form-item>
  54 + </el-form>
  55 + <template #footer>
  56 + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  57 + <el-button @click="dialogVisible = false">取 消</el-button>
  58 + </template>
  59 + </Dialog>
  60 +</template>
  61 +<script setup lang="ts">
  62 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  63 +import * as StudentApi from '@/api/infra/demo'
  64 +
  65 +const { t } = useI18n() // 国际化
  66 +const message = useMessage() // 消息弹窗
  67 +
  68 +const dialogVisible = ref(false) // 弹窗的是否展示
  69 +const dialogTitle = ref('') // 弹窗的标题
  70 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  71 +const formType = ref('') // 表单的类型:create - 新增;update - 修改
  72 +const formData = ref({
  73 + id: undefined,
  74 + name: undefined,
  75 + description: undefined,
  76 + birthday: undefined,
  77 + sex: undefined,
  78 + enabled: undefined,
  79 + avatar: undefined,
  80 + video: undefined,
  81 + memo: undefined
  82 +})
  83 +const formRules = reactive({
  84 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  85 + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }],
  86 + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }],
  87 + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }],
  88 + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }],
  89 + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }],
  90 + video: [{ required: true, message: '附件不能为空', trigger: 'blur' }],
  91 + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }]
  92 +})
  93 +const formRef = ref() // 表单 Ref
  94 +
  95 +/** 打开弹窗 */
  96 +const open = async (type: string, id?: number) => {
  97 + dialogVisible.value = true
  98 + dialogTitle.value = t('action.' + type)
  99 + formType.value = type
  100 + resetForm()
  101 + // 修改时,设置数据
  102 + if (id) {
  103 + formLoading.value = true
  104 + try {
  105 + formData.value = await StudentApi.getStudent(id)
  106 + } finally {
  107 + formLoading.value = false
  108 + }
  109 + }
  110 +}
  111 +defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  112 +
  113 +/** 提交表单 */
  114 +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  115 +const submitForm = async () => {
  116 + // 校验表单
  117 + await formRef.value.validate()
  118 + // 提交请求
  119 + formLoading.value = true
  120 + try {
  121 + const data = formData.value as unknown as StudentApi.StudentVO
  122 + if (formType.value === 'create') {
  123 + await StudentApi.createStudent(data)
  124 + message.success(t('common.createSuccess'))
  125 + } else {
  126 + await StudentApi.updateStudent(data)
  127 + message.success(t('common.updateSuccess'))
  128 + }
  129 + dialogVisible.value = false
  130 + // 发送操作成功的事件
  131 + emit('success')
  132 + } finally {
  133 + formLoading.value = false
  134 + }
  135 +}
  136 +
  137 +/** 重置表单 */
  138 +const resetForm = () => {
  139 + formData.value = {
  140 + id: undefined,
  141 + name: undefined,
  142 + description: undefined,
  143 + birthday: undefined,
  144 + sex: undefined,
  145 + enabled: undefined,
  146 + avatar: undefined,
  147 + video: undefined,
  148 + memo: undefined
  149 + }
  150 + formRef.value?.resetFields()
  151 +}
  152 +</script>
0 153 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/vue/index 0 → 100644
  1 +<template>
  2 + <ContentWrap>
  3 + <!-- 搜索工作栏 -->
  4 + <el-form
  5 + class="-mb-15px"
  6 + :model="queryParams"
  7 + ref="queryFormRef"
  8 + :inline="true"
  9 + label-width="68px"
  10 + >
  11 + <el-form-item label="名字" prop="name">
  12 + <el-input
  13 + v-model="queryParams.name"
  14 + placeholder="请输入名字"
  15 + clearable
  16 + @keyup.enter="handleQuery"
  17 + class="!w-240px"
  18 + />
  19 + </el-form-item>
  20 + <el-form-item label="出生日期" prop="birthday">
  21 + <el-date-picker
  22 + v-model="queryParams.birthday"
  23 + value-format="YYYY-MM-DD"
  24 + type="date"
  25 + placeholder="选择出生日期"
  26 + clearable
  27 + class="!w-240px"
  28 + />
  29 + </el-form-item>
  30 + <el-form-item label="性别" prop="sex">
  31 + <el-select
  32 + v-model="queryParams.sex"
  33 + placeholder="请选择性别"
  34 + clearable
  35 + class="!w-240px"
  36 + >
  37 + <el-option
  38 + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"
  39 + :key="dict.value"
  40 + :label="dict.label"
  41 + :value="dict.value"
  42 + />
  43 + </el-select>
  44 + </el-form-item>
  45 + <el-form-item label="是否有效" prop="enabled">
  46 + <el-select
  47 + v-model="queryParams.enabled"
  48 + placeholder="请选择是否有效"
  49 + clearable
  50 + class="!w-240px"
  51 + >
  52 + <el-option
  53 + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
  54 + :key="dict.value"
  55 + :label="dict.label"
  56 + :value="dict.value"
  57 + />
  58 + </el-select>
  59 + </el-form-item>
  60 + <el-form-item label="创建时间" prop="createTime">
  61 + <el-date-picker
  62 + v-model="queryParams.createTime"
  63 + value-format="YYYY-MM-DD HH:mm:ss"
  64 + type="daterange"
  65 + start-placeholder="开始日期"
  66 + end-placeholder="结束日期"
  67 + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  68 + class="!w-240px"
  69 + />
  70 + </el-form-item>
  71 + <el-form-item>
  72 + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
  73 + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
  74 + <el-button
  75 + type="primary"
  76 + plain
  77 + @click="openForm('create')"
  78 + v-hasPermi="['infra:student:create']"
  79 + >
  80 + <Icon icon="ep:plus" class="mr-5px" /> 新增
  81 + </el-button>
  82 + <el-button
  83 + type="success"
  84 + plain
  85 + @click="handleExport"
  86 + :loading="exportLoading"
  87 + v-hasPermi="['infra:student:export']"
  88 + >
  89 + <Icon icon="ep:download" class="mr-5px" /> 导出
  90 + </el-button>
  91 + </el-form-item>
  92 + </el-form>
  93 + </ContentWrap>
  94 +
  95 + <!-- 列表 -->
  96 + <ContentWrap>
  97 + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
  98 + <el-table-column label="编号" align="center" prop="id" />
  99 + <el-table-column label="名字" align="center" prop="name" />
  100 + <el-table-column label="简介" align="center" prop="description" />
  101 + <el-table-column
  102 + label="出生日期"
  103 + align="center"
  104 + prop="birthday"
  105 + :formatter="dateFormatter"
  106 + width="180px"
  107 + />
  108 + <el-table-column label="性别" align="center" prop="sex">
  109 + <template #default="scope">
  110 + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" />
  111 + </template>
  112 + </el-table-column>
  113 + <el-table-column label="是否有效" align="center" prop="enabled">
  114 + <template #default="scope">
  115 + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
  116 + </template>
  117 + </el-table-column>
  118 + <el-table-column label="头像" align="center" prop="avatar" />
  119 + <el-table-column label="附件" align="center" prop="video" />
  120 + <el-table-column label="备注" align="center" prop="memo" />
  121 + <el-table-column
  122 + label="创建时间"
  123 + align="center"
  124 + prop="createTime"
  125 + :formatter="dateFormatter"
  126 + width="180px"
  127 + />
  128 + <el-table-column label="操作" align="center">
  129 + <template #default="scope">
  130 + <el-button
  131 + link
  132 + type="primary"
  133 + @click="openForm('update', scope.row.id)"
  134 + v-hasPermi="['infra:student:update']"
  135 + >
  136 + 编辑
  137 + </el-button>
  138 + <el-button
  139 + link
  140 + type="danger"
  141 + @click="handleDelete(scope.row.id)"
  142 + v-hasPermi="['infra:student:delete']"
  143 + >
  144 + 删除
  145 + </el-button>
  146 + </template>
  147 + </el-table-column>
  148 + </el-table>
  149 + <!-- 分页 -->
  150 + <Pagination
  151 + :total="total"
  152 + v-model:page="queryParams.pageNo"
  153 + v-model:limit="queryParams.pageSize"
  154 + @pagination="getList"
  155 + />
  156 + </ContentWrap>
  157 +
  158 + <!-- 表单弹窗:添加/修改 -->
  159 + <StudentForm ref="formRef" @success="getList" />
  160 +</template>
  161 +
  162 +<script setup lang="ts">
  163 +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  164 +import { dateFormatter } from '@/utils/formatTime'
  165 +import download from '@/utils/download'
  166 +import * as StudentApi from '@/api/infra/demo'
  167 +import StudentForm from './StudentForm.vue'
  168 +
  169 +defineOptions({ name: 'InfraStudent' })
  170 +
  171 +const message = useMessage() // 消息弹窗
  172 +const { t } = useI18n() // 国际化
  173 +
  174 +const loading = ref(true) // 列表的加载中
  175 +const list = ref([]) // 列表的数据
  176 +const total = ref(0) // 列表的总页数
  177 +const queryParams = reactive({
  178 + pageNo: 1,
  179 + pageSize: 10,
  180 + name: null,
  181 + birthday: null,
  182 + birthday: [],
  183 + sex: null,
  184 + enabled: null,
  185 + createTime: []
  186 +})
  187 +const queryFormRef = ref() // 搜索的表单
  188 +const exportLoading = ref(false) // 导出的加载中
  189 +
  190 +/** 查询列表 */
  191 +const getList = async () => {
  192 + loading.value = true
  193 + try {
  194 + const data = await StudentApi.getStudentPage(queryParams)
  195 + list.value = data.list
  196 + total.value = data.total
  197 + } finally {
  198 + loading.value = false
  199 + }
  200 +}
  201 +
  202 +/** 搜索按钮操作 */
  203 +const handleQuery = () => {
  204 + queryParams.pageNo = 1
  205 + getList()
  206 +}
  207 +
  208 +/** 重置按钮操作 */
  209 +const resetQuery = () => {
  210 + queryFormRef.value.resetFields()
  211 + handleQuery()
  212 +}
  213 +
  214 +/** 添加/修改操作 */
  215 +const formRef = ref()
  216 +const openForm = (type: string, id?: number) => {
  217 + formRef.value.open(type, id)
  218 +}
  219 +
  220 +/** 删除按钮操作 */
  221 +const handleDelete = async (id: number) => {
  222 + try {
  223 + // 删除的二次确认
  224 + await message.delConfirm()
  225 + // 发起删除
  226 + await StudentApi.deleteStudent(id)
  227 + message.success(t('common.delSuccess'))
  228 + // 刷新列表
  229 + await getList()
  230 + } catch {}
  231 +}
  232 +
  233 +/** 导出按钮操作 */
  234 +const handleExport = async () => {
  235 + try {
  236 + // 导出的二次确认
  237 + await message.exportConfirm()
  238 + // 发起导出
  239 + exportLoading.value = true
  240 + const data = await StudentApi.exportStudent(queryParams)
  241 + download.excel(data, '学生.xls')
  242 + } catch {
  243 + } finally {
  244 + exportLoading.value = false
  245 + }
  246 +}
  247 +
  248 +/** 初始化 **/
  249 +onMounted(() => {
  250 + getList()
  251 +})
  252 +</script>
0 253 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one/xml/InfraStudentMapper 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraStudentMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/assert.json 0 → 100644
  1 +[ {
  2 + "contentPath" : "java/InfraCategoryListReqVO",
  3 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategoryListReqVO.java"
  4 +}, {
  5 + "contentPath" : "java/InfraCategoryRespVO",
  6 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategoryRespVO.java"
  7 +}, {
  8 + "contentPath" : "java/InfraCategorySaveReqVO",
  9 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/vo/InfraCategorySaveReqVO.java"
  10 +}, {
  11 + "contentPath" : "java/InfraCategoryController",
  12 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/controller/admin/demo/InfraCategoryController.java"
  13 +}, {
  14 + "contentPath" : "java/InfraCategoryDO",
  15 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/demo/InfraCategoryDO.java"
  16 +}, {
  17 + "contentPath" : "java/InfraCategoryMapper",
  18 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/mysql/demo/InfraCategoryMapper.java"
  19 +}, {
  20 + "contentPath" : "xml/InfraCategoryMapper",
  21 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/resources/mapper/demo/InfraCategoryMapper.xml"
  22 +}, {
  23 + "contentPath" : "java/InfraCategoryServiceImpl",
  24 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryServiceImpl.java"
  25 +}, {
  26 + "contentPath" : "java/InfraCategoryService",
  27 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryService.java"
  28 +}, {
  29 + "contentPath" : "java/InfraCategoryServiceImplTest",
  30 + "filePath" : "yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/demo/InfraCategoryServiceImplTest.java"
  31 +}, {
  32 + "contentPath" : "java/ErrorCodeConstants_手动操作",
  33 + "filePath" : "yudao-module-infra/yudao-module-infra-api/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-vue3/src/views/infra/demo/index.vue"
  43 +}, {
  44 + "contentPath" : "vue/CategoryForm",
  45 + "filePath" : "yudao-ui-admin-vue3/src/views/infra/demo/CategoryForm.vue"
  46 +}, {
  47 + "contentPath" : "ts/index",
  48 + "filePath" : "yudao-ui-admin-vue3/src/api/infra/demo/index.ts"
  49 +} ]
0 50 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/ErrorCodeConstants_手动操作 0 → 100644
  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");
0 9 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategoryController 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo;
  2 +
  3 +import org.springframework.web.bind.annotation.*;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.security.access.prepost.PreAuthorize;
  7 +import io.swagger.v3.oas.annotations.tags.Tag;
  8 +import io.swagger.v3.oas.annotations.Parameter;
  9 +import io.swagger.v3.oas.annotations.Operation;
  10 +
  11 +import javax.validation.constraints.*;
  12 +import javax.validation.*;
  13 +import javax.servlet.http.*;
  14 +import java.util.*;
  15 +import java.io.IOException;
  16 +
  17 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  18 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  19 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  20 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  24 +
  25 +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
  26 +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*;
  27 +
  28 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  29 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO;
  30 +import cn.iocoder.yudao.module.infra.service.demo.InfraCategoryService;
  31 +
  32 +@Tag(name = "管理后台 - 分类")
  33 +@RestController
  34 +@RequestMapping("/infra/category")
  35 +@Validated
  36 +public class InfraCategoryController {
  37 +
  38 + @Resource
  39 + private InfraCategoryService categoryService;
  40 +
  41 + @PostMapping("/create")
  42 + @Operation(summary = "创建分类")
  43 + @PreAuthorize("@ss.hasPermission('infra:category:create')")
  44 + public CommonResult<Long> createCategory(@Valid @RequestBody InfraCategorySaveReqVO createReqVO) {
  45 + return success(categoryService.createCategory(createReqVO));
  46 + }
  47 +
  48 + @PutMapping("/update")
  49 + @Operation(summary = "更新分类")
  50 + @PreAuthorize("@ss.hasPermission('infra:category:update')")
  51 + public CommonResult<Boolean> updateCategory(@Valid @RequestBody InfraCategorySaveReqVO updateReqVO) {
  52 + categoryService.updateCategory(updateReqVO);
  53 + return success(true);
  54 + }
  55 +
  56 + @DeleteMapping("/delete")
  57 + @Operation(summary = "删除分类")
  58 + @Parameter(name = "id", description = "编号", required = true)
  59 + @PreAuthorize("@ss.hasPermission('infra:category:delete')")
  60 + public CommonResult<Boolean> deleteCategory(@RequestParam("id") Long id) {
  61 + categoryService.deleteCategory(id);
  62 + return success(true);
  63 + }
  64 +
  65 + @GetMapping("/get")
  66 + @Operation(summary = "获得分类")
  67 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  68 + @PreAuthorize("@ss.hasPermission('infra:category:query')")
  69 + public CommonResult<InfraCategoryRespVO> getCategory(@RequestParam("id") Long id) {
  70 + InfraCategoryDO category = categoryService.getCategory(id);
  71 + return success(BeanUtils.toBean(category, InfraCategoryRespVO.class));
  72 + }
  73 +
  74 + @GetMapping("/list")
  75 + @Operation(summary = "获得分类列表")
  76 + @PreAuthorize("@ss.hasPermission('infra:category:query')")
  77 + public CommonResult<List<InfraCategoryRespVO>> getCategoryList(@Valid InfraCategoryListReqVO listReqVO) {
  78 + List<InfraCategoryDO> list = categoryService.getCategoryList(listReqVO);
  79 + return success(BeanUtils.toBean(list, InfraCategoryRespVO.class));
  80 + }
  81 +
  82 + @GetMapping("/export-excel")
  83 + @Operation(summary = "导出分类 Excel")
  84 + @PreAuthorize("@ss.hasPermission('infra:category:export')")
  85 + @OperateLog(type = EXPORT)
  86 + public void exportCategoryExcel(@Valid InfraCategoryListReqVO listReqVO,
  87 + HttpServletResponse response) throws IOException {
  88 + List<InfraCategoryDO> list = categoryService.getCategoryList(listReqVO);
  89 + // 导出 Excel
  90 + ExcelUtils.write(response, "分类.xls", "数据", InfraCategoryRespVO.class,
  91 + BeanUtils.toBean(list, InfraCategoryRespVO.class));
  92 + }
  93 +
  94 +}
0 95 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategoryDO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.dataobject.demo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import com.baomidou.mybatisplus.annotation.*;
  6 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  7 +
  8 +/**
  9 + * 分类 DO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@TableName("infra_category")
  14 +@KeySequence("infra_category_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +@Builder
  19 +@NoArgsConstructor
  20 +@AllArgsConstructor
  21 +public class InfraCategoryDO extends BaseDO {
  22 +
  23 + public static final Long PARENT_ID_ROOT = 0L;
  24 +
  25 + /**
  26 + * 编号
  27 + */
  28 + @TableId
  29 + private Long id;
  30 + /**
  31 + * 名字
  32 + */
  33 + private String name;
  34 + /**
  35 + * 父编号
  36 + */
  37 + private Long parentId;
  38 +
  39 +}
0 40 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategoryListReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import lombok.*;
  4 +import java.util.*;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +
  8 +@Schema(description = "管理后台 - 分类列表 Request VO")
  9 +@Data
  10 +public class InfraCategoryListReqVO {
  11 +
  12 + @Schema(description = "名字", example = "芋头")
  13 + private String name;
  14 +
  15 +}
0 16 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategoryMapper 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.dal.mysql.demo;
  2 +
  3 +import java.util.*;
  4 +
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  7 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  8 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO;
  9 +import org.apache.ibatis.annotations.Mapper;
  10 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  11 +
  12 +/**
  13 + * 分类 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface InfraCategoryMapper extends BaseMapperX<InfraCategoryDO> {
  19 +
  20 + default List<InfraCategoryDO> selectList(InfraCategoryListReqVO reqVO) {
  21 + return selectList(new LambdaQueryWrapperX<InfraCategoryDO>()
  22 + .likeIfPresent(InfraCategoryDO::getName, reqVO.getName())
  23 + .orderByDesc(InfraCategoryDO::getId));
  24 + }
  25 +
  26 + default InfraCategoryDO selectByParentIdAndName(Long parentId, String name) {
  27 + return selectOne(InfraCategoryDO::getParentId, parentId, InfraCategoryDO::getName, name);
  28 + }
  29 +
  30 + default Long selectCountByParentId(Long parentId) {
  31 + return selectCount(InfraCategoryDO::getParentId, parentId);
  32 + }
  33 +
  34 +}
0 35 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategoryRespVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import java.util.*;
  7 +import com.alibaba.excel.annotation.*;
  8 +
  9 +@Schema(description = "管理后台 - 分类 Response VO")
  10 +@Data
  11 +@ExcelIgnoreUnannotated
  12 +public class InfraCategoryRespVO {
  13 +
  14 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  15 + @ExcelProperty("编号")
  16 + private Long id;
  17 +
  18 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  19 + @ExcelProperty("名字")
  20 + private String name;
  21 +
  22 + @Schema(description = "父编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  23 + @ExcelProperty("父编号")
  24 + private Long parentId;
  25 +
  26 +}
0 27 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategorySaveReqVO 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.controller.admin.demo.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.*;
  5 +import java.util.*;
  6 +import javax.validation.constraints.*;
  7 +import java.util.*;
  8 +
  9 +@Schema(description = "管理后台 - 分类新增/修改 Request VO")
  10 +@Data
  11 +public class InfraCategorySaveReqVO {
  12 +
  13 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + private Long id;
  15 +
  16 + @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋头")
  17 + @NotEmpty(message = "名字不能为空")
  18 + private String name;
  19 +
  20 + @Schema(description = "父编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
  21 + @NotNull(message = "父编号不能为空")
  22 + private Long parentId;
  23 +
  24 +}
0 25 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategoryService 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import java.util.*;
  4 +import javax.validation.*;
  5 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  6 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  9 +
  10 +/**
  11 + * 分类 Service 接口
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +public interface InfraCategoryService {
  16 +
  17 + /**
  18 + * 创建分类
  19 + *
  20 + * @param createReqVO 创建信息
  21 + * @return 编号
  22 + */
  23 + Long createCategory(@Valid InfraCategorySaveReqVO createReqVO);
  24 +
  25 + /**
  26 + * 更新分类
  27 + *
  28 + * @param updateReqVO 更新信息
  29 + */
  30 + void updateCategory(@Valid InfraCategorySaveReqVO updateReqVO);
  31 +
  32 + /**
  33 + * 删除分类
  34 + *
  35 + * @param id 编号
  36 + */
  37 + void deleteCategory(Long id);
  38 +
  39 + /**
  40 + * 获得分类
  41 + *
  42 + * @param id 编号
  43 + * @return 分类
  44 + */
  45 + InfraCategoryDO getCategory(Long id);
  46 +
  47 + /**
  48 + * 获得分类列表
  49 + *
  50 + * @param listReqVO 查询条件
  51 + * @return 分类列表
  52 + */
  53 + List<InfraCategoryDO> getCategoryList(InfraCategoryListReqVO listReqVO);
  54 +
  55 +}
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategoryServiceImpl 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.springframework.stereotype.Service;
  4 +import javax.annotation.Resource;
  5 +import org.springframework.validation.annotation.Validated;
  6 +import org.springframework.transaction.annotation.Transactional;
  7 +
  8 +import java.util.*;
  9 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  10 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO;
  11 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  12 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  13 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  14 +
  15 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraCategoryMapper;
  16 +
  17 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  18 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  19 +
  20 +/**
  21 + * 分类 Service 实现类
  22 + *
  23 + * @author 芋道源码
  24 + */
  25 +@Service
  26 +@Validated
  27 +public class InfraCategoryServiceImpl implements InfraCategoryService {
  28 +
  29 + @Resource
  30 + private InfraCategoryMapper categoryMapper;
  31 +
  32 + @Override
  33 + public Long createCategory(InfraCategorySaveReqVO createReqVO) {
  34 + // 校验父编号的有效性
  35 + validateParentCategory(null, createReqVO.getParentId());
  36 + // 校验名字的唯一性
  37 + validateCategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
  38 +
  39 + // 插入
  40 + InfraCategoryDO category = BeanUtils.toBean(createReqVO, InfraCategoryDO.class);
  41 + categoryMapper.insert(category);
  42 + // 返回
  43 + return category.getId();
  44 + }
  45 +
  46 + @Override
  47 + public void updateCategory(InfraCategorySaveReqVO updateReqVO) {
  48 + // 校验存在
  49 + validateCategoryExists(updateReqVO.getId());
  50 + // 校验父编号的有效性
  51 + validateParentCategory(updateReqVO.getId(), updateReqVO.getParentId());
  52 + // 校验名字的唯一性
  53 + validateCategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
  54 +
  55 + // 更新
  56 + InfraCategoryDO updateObj = BeanUtils.toBean(updateReqVO, InfraCategoryDO.class);
  57 + categoryMapper.updateById(updateObj);
  58 + }
  59 +
  60 + @Override
  61 + public void deleteCategory(Long id) {
  62 + // 校验存在
  63 + validateCategoryExists(id);
  64 + // 校验是否有子分类
  65 + if (categoryMapper.selectCountByParentId(id) > 0) {
  66 + throw exception(CATEGORY_EXITS_CHILDREN);
  67 + }
  68 + // 删除
  69 + categoryMapper.deleteById(id);
  70 + }
  71 +
  72 + private void validateCategoryExists(Long id) {
  73 + if (categoryMapper.selectById(id) == null) {
  74 + throw exception(CATEGORY_NOT_EXISTS);
  75 + }
  76 + }
  77 +
  78 + private void validateParentCategory(Long id, Long parentId) {
  79 + if (parentId == null || CategoryDO.PARENT_ID_ROOT.equals(parentId)) {
  80 + return;
  81 + }
  82 + // 1. 不能设置自己为父分类
  83 + if (Objects.equals(id, parentId)) {
  84 + throw exception(CATEGORY_PARENT_ERROR);
  85 + }
  86 + // 2. 父分类不存在
  87 + CategoryDO parentCategory = categoryMapper.selectById(parentId);
  88 + if (parentCategory == null) {
  89 + throw exception(CATEGORY_PARENT_NOT_EXITS);
  90 + }
  91 + // 3. 递归校验父分类,如果父分类是自己的子分类,则报错,避免形成环路
  92 + if (id == null) { // id 为空,说明新增,不需要考虑环路
  93 + return;
  94 + }
  95 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  96 + // 3.1 校验环路
  97 + parentId = parentCategory.getParentId();
  98 + if (Objects.equals(id, parentId)) {
  99 + throw exception(CATEGORY_PARENT_IS_CHILD);
  100 + }
  101 + // 3.2 继续递归下一级父分类
  102 + if (parentId == null || CategoryDO.PARENT_ID_ROOT.equals(parentId)) {
  103 + break;
  104 + }
  105 + parentCategory = categoryMapper.selectById(parentId);
  106 + if (parentCategory == null) {
  107 + break;
  108 + }
  109 + }
  110 + }
  111 +
  112 + private void validateCategoryNameUnique(Long id, Long parentId, String name) {
  113 + CategoryDO category = categoryMapper.selectByParentIdAndName(parentId, name);
  114 + if (category == null) {
  115 + return;
  116 + }
  117 + // 如果 id 为空,说明不用比较是否为相同 id 的分类
  118 + if (id == null) {
  119 + throw exception(CATEGORY_NAME_DUPLICATE);
  120 + }
  121 + if (!Objects.equals(category.getId(), id)) {
  122 + throw exception(CATEGORY_NAME_DUPLICATE);
  123 + }
  124 + }
  125 +
  126 + @Override
  127 + public InfraCategoryDO getCategory(Long id) {
  128 + return categoryMapper.selectById(id);
  129 + }
  130 +
  131 + @Override
  132 + public List<InfraCategoryDO> getCategoryList(InfraCategoryListReqVO listReqVO) {
  133 + return categoryMapper.selectList(listReqVO);
  134 + }
  135 +
  136 +}
0 137 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/java/InfraCategoryServiceImplTest 0 → 100644
  1 +package cn.iocoder.yudao.module.infra.service.demo;
  2 +
  3 +import org.junit.jupiter.api.Disabled;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.boot.test.mock.mockito.MockBean;
  6 +
  7 +import javax.annotation.Resource;
  8 +
  9 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  10 +
  11 +import cn.iocoder.yudao.module.infra.controller.admin.demo.vo.*;
  12 +import cn.iocoder.yudao.module.infra.dal.dataobject.demo.InfraCategoryDO;
  13 +import cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraCategoryMapper;
  14 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  15 +
  16 +import javax.annotation.Resource;
  17 +import org.springframework.context.annotation.Import;
  18 +import java.util.*;
  19 +import java.time.LocalDateTime;
  20 +
  21 +import static cn.hutool.core.util.RandomUtil.*;
  22 +import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.*;
  23 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*;
  24 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
  25 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  26 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*;
  27 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
  28 +import static org.junit.jupiter.api.Assertions.*;
  29 +import static org.mockito.Mockito.*;
  30 +
  31 +/**
  32 + * {@link InfraCategoryServiceImpl} 的单元测试类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Import(InfraCategoryServiceImpl.class)
  37 +public class InfraCategoryServiceImplTest extends BaseDbUnitTest {
  38 +
  39 + @Resource
  40 + private InfraCategoryServiceImpl categoryService;
  41 +
  42 + @Resource
  43 + private InfraCategoryMapper categoryMapper;
  44 +
  45 + @Test
  46 + public void testCreateCategory_success() {
  47 + // 准备参数
  48 + InfraCategorySaveReqVO createReqVO = randomPojo(InfraCategorySaveReqVO.class).setId(null);
  49 +
  50 + // 调用
  51 + Long categoryId = categoryService.createCategory(createReqVO);
  52 + // 断言
  53 + assertNotNull(categoryId);
  54 + // 校验记录的属性是否正确
  55 + InfraCategoryDO category = categoryMapper.selectById(categoryId);
  56 + assertPojoEquals(createReqVO, category, "id");
  57 + }
  58 +
  59 + @Test
  60 + public void testUpdateCategory_success() {
  61 + // mock 数据
  62 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class);
  63 + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据
  64 + // 准备参数
  65 + InfraCategorySaveReqVO updateReqVO = randomPojo(InfraCategorySaveReqVO.class, o -> {
  66 + o.setId(dbCategory.getId()); // 设置更新的 ID
  67 + });
  68 +
  69 + // 调用
  70 + categoryService.updateCategory(updateReqVO);
  71 + // 校验是否更新正确
  72 + InfraCategoryDO category = categoryMapper.selectById(updateReqVO.getId()); // 获取最新的
  73 + assertPojoEquals(updateReqVO, category);
  74 + }
  75 +
  76 + @Test
  77 + public void testUpdateCategory_notExists() {
  78 + // 准备参数
  79 + InfraCategorySaveReqVO updateReqVO = randomPojo(InfraCategorySaveReqVO.class);
  80 +
  81 + // 调用, 并断言异常
  82 + assertServiceException(() -> categoryService.updateCategory(updateReqVO), CATEGORY_NOT_EXISTS);
  83 + }
  84 +
  85 + @Test
  86 + public void testDeleteCategory_success() {
  87 + // mock 数据
  88 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class);
  89 + categoryMapper.insert(dbCategory);// @Sql: 先插入出一条存在的数据
  90 + // 准备参数
  91 + Long id = dbCategory.getId();
  92 +
  93 + // 调用
  94 + categoryService.deleteCategory(id);
  95 + // 校验数据不存在了
  96 + assertNull(categoryMapper.selectById(id));
  97 + }
  98 +
  99 + @Test
  100 + public void testDeleteCategory_notExists() {
  101 + // 准备参数
  102 + Long id = randomLongId();
  103 +
  104 + // 调用, 并断言异常
  105 + assertServiceException(() -> categoryService.deleteCategory(id), CATEGORY_NOT_EXISTS);
  106 + }
  107 +
  108 + @Test
  109 + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解
  110 + public void testGetCategoryList() {
  111 + // mock 数据
  112 + InfraCategoryDO dbCategory = randomPojo(InfraCategoryDO.class, o -> { // 等会查询到
  113 + o.setName(null);
  114 + });
  115 + categoryMapper.insert(dbCategory);
  116 + // 测试 name 不匹配
  117 + categoryMapper.insert(cloneIgnoreId(dbCategory, o -> o.setName(null)));
  118 + // 准备参数
  119 + InfraCategoryListReqVO reqVO = new InfraCategoryListReqVO();
  120 + reqVO.setName(null);
  121 +
  122 + // 调用
  123 + List<InfraCategoryDO> list = categoryService.getCategoryList(reqVO);
  124 + // 断言
  125 + assertEquals(1, list.size());
  126 + assertPojoEquals(dbCategory, list.get(0));
  127 + }
  128 +
  129 +}
0 130 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/sql/h2 0 → 100644
  1 +-- 将该建表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/create_tables.sql 文件里
  2 +CREATE TABLE IF NOT EXISTS "infra_category" (
  3 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  4 + "name" varchar NOT NULL,
  5 + "description" bigint NOT NULL,
  6 + PRIMARY KEY ("id")
  7 +) COMMENT '分类表';
  8 +
  9 +-- 将该删表 SQL 语句,添加到 yudao-module-infra-biz 模块的 test/resources/sql/clean.sql 文件里
  10 +DELETE FROM "infra_category";
0 11 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/sql/sql 0 → 100644
  1 +-- 菜单 SQL
  2 +INSERT INTO system_menu(
  3 + name, permission, type, sort, parent_id,
  4 + path, icon, component, status, component_name
  5 +)
  6 +VALUES (
  7 + '分类管理', '', 2, 0, 888,
  8 + 'category', '', 'infra/demo/index', 0, 'InfraCategory'
  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:category: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:category: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:category: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:category: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:category:export', 3, 5, @parentId,
  54 + '', '', '', 0
  55 +);
0 56 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/ts/index 0 → 100644
  1 +import request from '@/config/axios'
  2 +
  3 +export interface CategoryVO {
  4 + id: number
  5 + name: string
  6 + parentId: number
  7 +}
  8 +
  9 +// 查询分类列表
  10 +export const getCategoryList = async (params) => {
  11 + return await request.get({ url: `/infra/category/list`, params })
  12 +}
  13 +
  14 +// 查询分类详情
  15 +export const getCategory = async (id: number) => {
  16 + return await request.get({ url: `/infra/category/get?id=` + id })
  17 +}
  18 +
  19 +// 新增分类
  20 +export const createCategory = async (data: CategoryVO) => {
  21 + return await request.post({ url: `/infra/category/create`, data })
  22 +}
  23 +
  24 +// 修改分类
  25 +export const updateCategory = async (data: CategoryVO) => {
  26 + return await request.put({ url: `/infra/category/update`, data })
  27 +}
  28 +
  29 +// 删除分类
  30 +export const deleteCategory = async (id: number) => {
  31 + return await request.delete({ url: `/infra/category/delete?id=` + id })
  32 +}
  33 +
  34 +// 导出分类 Excel
  35 +export const exportCategory = async (params) => {
  36 + return await request.download({ url: `/infra/category/export-excel`, params })
  37 +}
0 38 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/vue/CategoryForm 0 → 100644
  1 +<template>
  2 + <Dialog :title="dialogTitle" v-model="dialogVisible">
  3 + <el-form
  4 + ref="formRef"
  5 + :model="formData"
  6 + :rules="formRules"
  7 + label-width="100px"
  8 + v-loading="formLoading"
  9 + >
  10 + <el-form-item label="名字" prop="name">
  11 + <el-input v-model="formData.name" placeholder="请输入名字" />
  12 + </el-form-item>
  13 + <el-form-item label="父编号" prop="parentId">
  14 + <el-tree-select
  15 + v-model="formData.parentId"
  16 + :data="categoryTree"
  17 + :props="defaultProps"
  18 + check-strictly
  19 + default-expand-all
  20 + placeholder="请选择父编号"
  21 + />
  22 + </el-form-item>
  23 + </el-form>
  24 + <template #footer>
  25 + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
  26 + <el-button @click="dialogVisible = false">取 消</el-button>
  27 + </template>
  28 + </Dialog>
  29 +</template>
  30 +<script setup lang="ts">
  31 +import * as CategoryApi from '@/api/infra/demo'
  32 +import { defaultProps, handleTree } from '@/utils/tree'
  33 +
  34 +const { t } = useI18n() // 国际化
  35 +const message = useMessage() // 消息弹窗
  36 +
  37 +const dialogVisible = ref(false) // 弹窗的是否展示
  38 +const dialogTitle = ref('') // 弹窗的标题
  39 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
  40 +const formType = ref('') // 表单的类型:create - 新增;update - 修改
  41 +const formData = ref({
  42 + id: undefined,
  43 + name: undefined,
  44 + parentId: undefined
  45 +})
  46 +const formRules = reactive({
  47 + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }],
  48 + parentId: [{ required: true, message: '父编号不能为空', trigger: 'blur' }]
  49 +})
  50 +const formRef = ref() // 表单 Ref
  51 +const categoryTree = ref() // 树形结构
  52 +
  53 +/** 打开弹窗 */
  54 +const open = async (type: string, id?: number) => {
  55 + dialogVisible.value = true
  56 + dialogTitle.value = t('action.' + type)
  57 + formType.value = type
  58 + resetForm()
  59 + // 修改时,设置数据
  60 + if (id) {
  61 + formLoading.value = true
  62 + try {
  63 + formData.value = await CategoryApi.getCategory(id)
  64 + } finally {
  65 + formLoading.value = false
  66 + }
  67 + }
  68 + await getCategoryTree()
  69 +}
  70 +defineExpose({ open }) // 提供 open 方法,用于打开弹窗
  71 +
  72 +/** 提交表单 */
  73 +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
  74 +const submitForm = async () => {
  75 + // 校验表单
  76 + await formRef.value.validate()
  77 + // 提交请求
  78 + formLoading.value = true
  79 + try {
  80 + const data = formData.value as unknown as CategoryApi.CategoryVO
  81 + if (formType.value === 'create') {
  82 + await CategoryApi.createCategory(data)
  83 + message.success(t('common.createSuccess'))
  84 + } else {
  85 + await CategoryApi.updateCategory(data)
  86 + message.success(t('common.updateSuccess'))
  87 + }
  88 + dialogVisible.value = false
  89 + // 发送操作成功的事件
  90 + emit('success')
  91 + } finally {
  92 + formLoading.value = false
  93 + }
  94 +}
  95 +
  96 +/** 重置表单 */
  97 +const resetForm = () => {
  98 + formData.value = {
  99 + id: undefined,
  100 + name: undefined,
  101 + parentId: undefined
  102 + }
  103 + formRef.value?.resetFields()
  104 +}
  105 +
  106 +/** 获得分类树 */
  107 +const getCategoryTree = async () => {
  108 + categoryTree.value = []
  109 + const data = await CategoryApi.getCategoryList()
  110 + const root: Tree = { id: 0, name: '顶级分类', children: [] }
  111 + root.children = handleTree(data, 'id', 'parentId')
  112 + categoryTree.value.push(root)
  113 +}
  114 +</script>
0 115 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/vue/index 0 → 100644
  1 +<template>
  2 + <ContentWrap>
  3 + <!-- 搜索工作栏 -->
  4 + <el-form
  5 + class="-mb-15px"
  6 + :model="queryParams"
  7 + ref="queryFormRef"
  8 + :inline="true"
  9 + label-width="68px"
  10 + >
  11 + <el-form-item label="名字" prop="name">
  12 + <el-input
  13 + v-model="queryParams.name"
  14 + placeholder="请输入名字"
  15 + clearable
  16 + @keyup.enter="handleQuery"
  17 + class="!w-240px"
  18 + />
  19 + </el-form-item>
  20 + <el-form-item>
  21 + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
  22 + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
  23 + <el-button
  24 + type="primary"
  25 + plain
  26 + @click="openForm('create')"
  27 + v-hasPermi="['infra:category:create']"
  28 + >
  29 + <Icon icon="ep:plus" class="mr-5px" /> 新增
  30 + </el-button>
  31 + <el-button
  32 + type="success"
  33 + plain
  34 + @click="handleExport"
  35 + :loading="exportLoading"
  36 + v-hasPermi="['infra:category:export']"
  37 + >
  38 + <Icon icon="ep:download" class="mr-5px" /> 导出
  39 + </el-button>
  40 + <el-button type="danger" plain @click="toggleExpandAll">
  41 + <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
  42 + </el-button>
  43 + </el-form-item>
  44 + </el-form>
  45 + </ContentWrap>
  46 +
  47 + <!-- 列表 -->
  48 + <ContentWrap>
  49 + <el-table
  50 + v-loading="loading"
  51 + :data="list"
  52 + :stripe="true"
  53 + :show-overflow-tooltip="true"
  54 + row-key="id"
  55 + :default-expand-all="isExpandAll"
  56 + v-if="refreshTable"
  57 + >
  58 + <el-table-column label="编号" align="center" prop="id" />
  59 + <el-table-column label="名字" align="center" prop="name" />
  60 + <el-table-column label="父编号" align="center" prop="parentId" />
  61 + <el-table-column label="操作" align="center">
  62 + <template #default="scope">
  63 + <el-button
  64 + link
  65 + type="primary"
  66 + @click="openForm('update', scope.row.id)"
  67 + v-hasPermi="['infra:category:update']"
  68 + >
  69 + 编辑
  70 + </el-button>
  71 + <el-button
  72 + link
  73 + type="danger"
  74 + @click="handleDelete(scope.row.id)"
  75 + v-hasPermi="['infra:category:delete']"
  76 + >
  77 + 删除
  78 + </el-button>
  79 + </template>
  80 + </el-table-column>
  81 + </el-table>
  82 + <!-- 分页 -->
  83 + <Pagination
  84 + :total="total"
  85 + v-model:page="queryParams.pageNo"
  86 + v-model:limit="queryParams.pageSize"
  87 + @pagination="getList"
  88 + />
  89 + </ContentWrap>
  90 +
  91 + <!-- 表单弹窗:添加/修改 -->
  92 + <CategoryForm ref="formRef" @success="getList" />
  93 +</template>
  94 +
  95 +<script setup lang="ts">
  96 +import { handleTree } from '@/utils/tree'
  97 +import download from '@/utils/download'
  98 +import * as CategoryApi from '@/api/infra/demo'
  99 +import CategoryForm from './CategoryForm.vue'
  100 +
  101 +defineOptions({ name: 'InfraCategory' })
  102 +
  103 +const message = useMessage() // 消息弹窗
  104 +const { t } = useI18n() // 国际化
  105 +
  106 +const loading = ref(true) // 列表的加载中
  107 +const list = ref([]) // 列表的数据
  108 +const queryParams = reactive({
  109 + name: null
  110 +})
  111 +const queryFormRef = ref() // 搜索的表单
  112 +const exportLoading = ref(false) // 导出的加载中
  113 +
  114 +/** 查询列表 */
  115 +const getList = async () => {
  116 + loading.value = true
  117 + try {
  118 + const data = await CategoryApi.getCategoryList(queryParams)
  119 + list.value = handleTree(data, 'id', 'parentId')
  120 + } finally {
  121 + loading.value = false
  122 + }
  123 +}
  124 +
  125 +/** 搜索按钮操作 */
  126 +const handleQuery = () => {
  127 + queryParams.pageNo = 1
  128 + getList()
  129 +}
  130 +
  131 +/** 重置按钮操作 */
  132 +const resetQuery = () => {
  133 + queryFormRef.value.resetFields()
  134 + handleQuery()
  135 +}
  136 +
  137 +/** 添加/修改操作 */
  138 +const formRef = ref()
  139 +const openForm = (type: string, id?: number) => {
  140 + formRef.value.open(type, id)
  141 +}
  142 +
  143 +/** 删除按钮操作 */
  144 +const handleDelete = async (id: number) => {
  145 + try {
  146 + // 删除的二次确认
  147 + await message.delConfirm()
  148 + // 发起删除
  149 + await CategoryApi.deleteCategory(id)
  150 + message.success(t('common.delSuccess'))
  151 + // 刷新列表
  152 + await getList()
  153 + } catch {}
  154 +}
  155 +
  156 +/** 导出按钮操作 */
  157 +const handleExport = async () => {
  158 + try {
  159 + // 导出的二次确认
  160 + await message.exportConfirm()
  161 + // 发起导出
  162 + exportLoading.value = true
  163 + const data = await CategoryApi.exportCategory(queryParams)
  164 + download.excel(data, '分类.xls')
  165 + } catch {
  166 + } finally {
  167 + exportLoading.value = false
  168 + }
  169 +}
  170 +
  171 +/** 展开/折叠操作 */
  172 +const isExpandAll = ref(true) // 是否展开,默认全部展开
  173 +const refreshTable = ref(true) // 重新渲染表格状态
  174 +const toggleExpandAll = async () => {
  175 + refreshTable.value = false
  176 + isExpandAll.value = !isExpandAll.value
  177 + await nextTick()
  178 + refreshTable.value = true
  179 +}
  180 +
  181 +/** 初始化 **/
  182 +onMounted(() => {
  183 + getList()
  184 +})
  185 +</script>
0 186 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree/xml/InfraCategoryMapper 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3 +<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.demo.InfraCategoryMapper">
  4 +
  5 + <!--
  6 + 一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
  7 + 无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
  8 + 代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
  9 + 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
  10 + -->
  11 +
  12 +</mapper>
0 13 \ No newline at end of file
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/dept/DeptIdEnum.java deleted
1   -package cn.iocoder.yudao.module.system.enums.dept;
2   -
3   -import lombok.AllArgsConstructor;
4   -import lombok.Getter;
5   -
6   -/**
7   - * 部门编号枚举
8   - */
9   -@Getter
10   -@AllArgsConstructor
11   -public enum DeptIdEnum {
12   -
13   - /**
14   - * 根节点
15   - */
16   - ROOT(0L);
17   -
18   - private final Long id;
19   -
20   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/PostController.java
... ... @@ -2,16 +2,20 @@ package cn.iocoder.yudao.module.system.controller.admin.dept;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
5 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 8 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
7 9 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
8   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.*;
9   -import cn.iocoder.yudao.module.system.convert.dept.PostConvert;
  10 +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
  11 +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
  12 +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostRespVO;
  13 +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSimpleRespVO;
10 14 import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
11 15 import cn.iocoder.yudao.module.system.service.dept.PostService;
12   -import io.swagger.v3.oas.annotations.tags.Tag;
13   -import io.swagger.v3.oas.annotations.Parameter;
14 16 import io.swagger.v3.oas.annotations.Operation;
  17 +import io.swagger.v3.oas.annotations.Parameter;
  18 +import io.swagger.v3.oas.annotations.tags.Tag;
15 19 import org.springframework.security.access.prepost.PreAuthorize;
16 20 import org.springframework.validation.annotation.Validated;
17 21 import org.springframework.web.bind.annotation.*;
... ... @@ -39,16 +43,16 @@ public class PostController {
39 43 @PostMapping("/create")
40 44 @Operation(summary = "创建岗位")
41 45 @PreAuthorize("@ss.hasPermission('system:post:create')")
42   - public CommonResult<Long> createPost(@Valid @RequestBody PostCreateReqVO reqVO) {
43   - Long postId = postService.createPost(reqVO);
  46 + public CommonResult<Long> createPost(@Valid @RequestBody PostSaveReqVO createReqVO) {
  47 + Long postId = postService.createPost(createReqVO);
44 48 return success(postId);
45 49 }
46 50  
47 51 @PutMapping("/update")
48 52 @Operation(summary = "修改岗位")
49 53 @PreAuthorize("@ss.hasPermission('system:post:update')")
50   - public CommonResult<Boolean> updatePost(@Valid @RequestBody PostUpdateReqVO reqVO) {
51   - postService.updatePost(reqVO);
  54 + public CommonResult<Boolean> updatePost(@Valid @RequestBody PostSaveReqVO updateReqVO) {
  55 + postService.updatePost(updateReqVO);
52 56 return success(true);
53 57 }
54 58  
... ... @@ -65,35 +69,38 @@ public class PostController {
65 69 @Parameter(name = "id", description = "岗位编号", required = true, example = "1024")
66 70 @PreAuthorize("@ss.hasPermission('system:post:query')")
67 71 public CommonResult<PostRespVO> getPost(@RequestParam("id") Long id) {
68   - return success(PostConvert.INSTANCE.convert(postService.getPost(id)));
  72 + PostDO post = postService.getPost(id);
  73 + return success(BeanUtils.toBean(post, PostRespVO.class));
69 74 }
70 75  
71 76 @GetMapping("/list-all-simple")
72   - @Operation(summary = "获取岗位精简信息列表", description = "只包含被开启的岗位,主要用于前端的下拉选项")
  77 + @Operation(summary = "获取岗位全列表", description = "只包含被开启的岗位,主要用于前端的下拉选项")
73 78 public CommonResult<List<PostSimpleRespVO>> getSimplePostList() {
74 79 // 获得岗位列表,只要开启状态的
75 80 List<PostDO> list = postService.getPostList(null, Collections.singleton(CommonStatusEnum.ENABLE.getStatus()));
76 81 // 排序后,返回给前端
77 82 list.sort(Comparator.comparing(PostDO::getSort));
78   - return success(PostConvert.INSTANCE.convertList02(list));
  83 + return success(BeanUtils.toBean(list, PostSimpleRespVO.class));
79 84 }
80 85  
81 86 @GetMapping("/page")
82 87 @Operation(summary = "获得岗位分页列表")
83 88 @PreAuthorize("@ss.hasPermission('system:post:query')")
84   - public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO reqVO) {
85   - return success(PostConvert.INSTANCE.convertPage(postService.getPostPage(reqVO)));
  89 + public CommonResult<PageResult<PostRespVO>> getPostPage(@Validated PostPageReqVO pageReqVO) {
  90 + PageResult<PostDO> pageResult = postService.getPostPage(pageReqVO);
  91 + return success(BeanUtils.toBean(pageResult, PostRespVO.class));
86 92 }
87 93  
88 94 @GetMapping("/export")
89 95 @Operation(summary = "岗位管理")
90 96 @PreAuthorize("@ss.hasPermission('system:post:export')")
91 97 @OperateLog(type = EXPORT)
92   - public void export(HttpServletResponse response, @Validated PostExportReqVO reqVO) throws IOException {
93   - List<PostDO> posts = postService.getPostList(reqVO);
94   - List<PostExcelVO> data = PostConvert.INSTANCE.convertList03(posts);
  98 + public void export(HttpServletResponse response, @Validated PostPageReqVO reqVO) throws IOException {
  99 + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  100 + List<PostDO> list = postService.getPostPage(reqVO).getList();
95 101 // 输出
96   - ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostExcelVO.class, data);
  102 + ExcelUtils.write(response, "岗位数据.xls", "岗位列表", PostRespVO.class,
  103 + BeanUtils.toBean(list, PostRespVO.class));
97 104 }
98 105  
99 106 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostCreateReqVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -
7   -@Schema(description = "管理后台 - 岗位创建 Request VO")
8   -@Data
9   -@EqualsAndHashCode(callSuper = true)
10   -public class PostCreateReqVO extends PostBaseVO {
11   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostExcelVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
2   -
3   -import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
4   -import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
5   -import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
6   -import com.alibaba.excel.annotation.ExcelProperty;
7   -import lombok.Data;
8   -
9   -/**
10   - * 岗位 Excel 导出响应 VO
11   - */
12   -@Data
13   -public class PostExcelVO {
14   -
15   - @ExcelProperty("岗位序号")
16   - private Long id;
17   -
18   - @ExcelProperty("岗位编码")
19   - private String code;
20   -
21   - @ExcelProperty("岗位名称")
22   - private String name;
23   -
24   - @ExcelProperty("岗位排序")
25   - private Integer sort;
26   -
27   - @ExcelProperty(value = "状态", converter = DictConvert.class)
28   - @DictFormat(DictTypeConstants.COMMON_STATUS)
29   - private String status;
30   -
31   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostExportReqVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -
6   -@Schema(description = "管理后台 - 岗位导出 Request VO,参数和 PostExcelVO 是一致的")
7   -@Data
8   -public class PostExportReqVO {
9   -
10   - @Schema(description = "岗位编码,模糊匹配", example = "yudao")
11   - private String code;
12   -
13   - @Schema(description = "岗位名称,模糊匹配", example = "芋道")
14   - private String name;
15   -
16   - @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
17   - private Integer status;
18   -
19   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostListReqVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -
7   -@Schema(description = "管理后台 - 岗位列表 Request VO")
8   -@Data
9   -@EqualsAndHashCode(callSuper = true)
10   -public class PostListReqVO extends PostBaseVO {
11   -
12   - @Schema(description = "岗位名称,模糊匹配", example = "芋道")
13   - private String name;
14   -
15   - @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
16   - private Integer status;
17   -
18   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostRespVO.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
2 2  
  3 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  4 +import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
  5 +import com.alibaba.excel.annotation.ExcelProperty;
3 6 import io.swagger.v3.oas.annotations.media.Schema;
4 7 import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6 8  
7 9 import java.time.LocalDateTime;
8 10  
9 11 @Schema(description = "管理后台 - 岗位信息 Response VO")
10 12 @Data
11   -@EqualsAndHashCode(callSuper = true)
12   -public class PostRespVO extends PostBaseVO {
  13 +public class PostRespVO {
13 14  
14 15 @Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  16 + @ExcelProperty("岗位序号")
15 17 private Long id;
16 18  
17   - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
  19 + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
  20 + @ExcelProperty("岗位名称")
  21 + private String name;
  22 +
  23 + @Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
  24 + @ExcelProperty("岗位编码")
  25 + private String code;
  26 +
  27 + @Schema(description = "显示顺序不能为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  28 + @ExcelProperty("岗位排序")
  29 + private Integer sort;
  30 +
  31 + @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  32 + @DictFormat(DictTypeConstants.COMMON_STATUS)
  33 + private Integer status;
  34 +
  35 + @Schema(description = "备注", example = "快乐的备注")
  36 + private String remark;
  37 +
  38 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
18 39 private LocalDateTime createTime;
19 40  
20 41 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostBaseVO.java renamed to yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostSaveReqVO.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
2 5 import io.swagger.v3.oas.annotations.media.Schema;
3 6 import lombok.Data;
4 7  
... ... @@ -6,16 +9,16 @@ import javax.validation.constraints.NotBlank;
6 9 import javax.validation.constraints.NotNull;
7 10 import javax.validation.constraints.Size;
8 11  
9   -/**
10   - * 岗位 Base VO,提供给添加、修改、详细的子 VO 使用
11   - * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
12   - */
  12 +@Schema(description = "管理后台 - 岗位创建/修改 Request VO")
13 13 @Data
14   -public class PostBaseVO {
  14 +public class PostSaveReqVO {
  15 +
  16 + @Schema(description = "岗位编号", example = "1024")
  17 + private Long id;
15 18  
16   - @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小博主")
  19 + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
17 20 @NotBlank(message = "岗位名称不能为空")
18   - @Size(max = 50, message = "岗位名称长度不能超过50个字符")
  21 + @Size(max = 50, message = "岗位名称长度不能超过 50 个字符")
19 22 private String name;
20 23  
21 24 @Schema(description = "岗位编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
... ... @@ -27,10 +30,11 @@ public class PostBaseVO {
27 30 @NotNull(message = "显示顺序不能为空")
28 31 private Integer sort;
29 32  
30   - @Schema(description = "状态,参见 CommonStatusEnum 枚举类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  33 + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  34 + @InEnum(CommonStatusEnum.class)
31 35 private Integer status;
32 36  
33 37 @Schema(description = "备注", example = "快乐的备注")
34 38 private String remark;
35 39  
36 40 -}
  41 +}
37 42 \ No newline at end of file
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostSimpleRespVO.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
2 2  
  3 +import com.alibaba.excel.annotation.ExcelProperty;
3 4 import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.AllArgsConstructor;
5 5 import lombok.Data;
6   -import lombok.NoArgsConstructor;
7 6  
8   -@Schema(description = "管理后台 - 岗位精简信息 Response VO")
  7 +@Schema(description = "管理后台 - 岗位信息的精简 Response VO")
9 8 @Data
10   -@NoArgsConstructor
11   -@AllArgsConstructor
12 9 public class PostSimpleRespVO {
13 10  
14   - @Schema(description = "岗位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  11 + @Schema(description = "岗位序号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  12 + @ExcelProperty("岗位序号")
15 13 private Long id;
16 14  
17   - @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
  15 + @Schema(description = "岗位名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "小土豆")
  16 + @ExcelProperty("岗位名称")
18 17 private String name;
19 18  
20 19 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/post/PostUpdateReqVO.java deleted
1   -package cn.iocoder.yudao.module.system.controller.admin.dept.vo.post;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import lombok.Data;
5   -import lombok.EqualsAndHashCode;
6   -
7   -import javax.validation.constraints.NotNull;
8   -
9   -@Schema(description = "管理后台 - 岗位更新 Request VO")
10   -@Data
11   -@EqualsAndHashCode(callSuper = true)
12   -public class PostUpdateReqVO extends PostBaseVO {
13   -
14   - @Schema(description = "岗位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
15   - @NotNull(message = "岗位编号不能为空")
16   - private Long id;
17   -
18   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/dept/PostConvert.java deleted
1   -package cn.iocoder.yudao.module.system.convert.dept;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.*;
5   -import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
6   -import org.mapstruct.Mapper;
7   -import org.mapstruct.factory.Mappers;
8   -
9   -import java.util.List;
10   -
11   -@Mapper
12   -public interface PostConvert {
13   -
14   - PostConvert INSTANCE = Mappers.getMapper(PostConvert.class);
15   -
16   - List<PostSimpleRespVO> convertList02(List<PostDO> list);
17   -
18   - PageResult<PostRespVO> convertPage(PageResult<PostDO> page);
19   -
20   - PostRespVO convert(PostDO id);
21   -
22   - PostDO convert(PostCreateReqVO bean);
23   -
24   - PostDO convert(PostUpdateReqVO reqVO);
25   -
26   - List<PostExcelVO> convertList03(List<PostDO> list);
27   -
28   -}
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java
... ... @@ -21,6 +21,8 @@ import lombok.EqualsAndHashCode;
21 21 @EqualsAndHashCode(callSuper = true)
22 22 public class DeptDO extends TenantBaseDO {
23 23  
  24 + public static final Long PARENT_ID_ROOT = 0L;
  25 +
24 26 /**
25 27 * 部门ID
26 28 */
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/PostMapper.java
... ... @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.dal.mysql.dept;
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostExportReqVO;
7 6 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
8 7 import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
9 8 import org.apache.ibatis.annotations.Mapper;
... ... @@ -28,13 +27,6 @@ public interface PostMapper extends BaseMapperX&lt;PostDO&gt; {
28 27 .orderByDesc(PostDO::getId));
29 28 }
30 29  
31   - default List<PostDO> selectList(PostExportReqVO reqVO) {
32   - return selectList(new LambdaQueryWrapperX<PostDO>()
33   - .likeIfPresent(PostDO::getCode, reqVO.getCode())
34   - .likeIfPresent(PostDO::getName, reqVO.getName())
35   - .eqIfPresent(PostDO::getStatus, reqVO.getStatus()));
36   - }
37   -
38 30 default PostDO selectByName(String name) {
39 31 return selectOne(PostDO::getName, name);
40 32 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java
... ... @@ -11,7 +11,6 @@ import cn.iocoder.yudao.module.system.convert.dept.DeptConvert;
11 11 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
12 12 import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
13 13 import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
14   -import cn.iocoder.yudao.module.system.enums.dept.DeptIdEnum;
15 14 import com.google.common.annotations.VisibleForTesting;
16 15 import lombok.extern.slf4j.Slf4j;
17 16 import org.springframework.cache.annotation.CacheEvict;
... ... @@ -42,14 +41,17 @@ public class DeptServiceImpl implements DeptService {
42 41 @Override
43 42 @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
44 43 allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
45   - public Long createDept(DeptCreateReqVO reqVO) {
46   - // 校验正确性
47   - if (reqVO.getParentId() == null) {
48   - reqVO.setParentId(DeptIdEnum.ROOT.getId());
  44 + public Long createDept(DeptCreateReqVO createReqVO) {
  45 + if (createReqVO.getParentId() == null) {
  46 + createReqVO.setParentId(DeptDO.PARENT_ID_ROOT);
49 47 }
50   - validateForCreateOrUpdate(null, reqVO.getParentId(), reqVO.getName());
  48 + // 校验父部门的有效性
  49 + validateParentDept(null, createReqVO.getParentId());
  50 + // 校验部门名的唯一性
  51 + validateDeptNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
  52 +
51 53 // 插入部门
52   - DeptDO dept = DeptConvert.INSTANCE.convert(reqVO);
  54 + DeptDO dept = DeptConvert.INSTANCE.convert(createReqVO);
53 55 deptMapper.insert(dept);
54 56 return dept.getId();
55 57 }
... ... @@ -57,14 +59,19 @@ public class DeptServiceImpl implements DeptService {
57 59 @Override
58 60 @CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
59 61 allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
60   - public void updateDept(DeptUpdateReqVO reqVO) {
61   - // 校验正确性
62   - if (reqVO.getParentId() == null) {
63   - reqVO.setParentId(DeptIdEnum.ROOT.getId());
  62 + public void updateDept(DeptUpdateReqVO updateReqVO) {
  63 + if (updateReqVO.getParentId() == null) {
  64 + updateReqVO.setParentId(DeptDO.PARENT_ID_ROOT);
64 65 }
65   - validateForCreateOrUpdate(reqVO.getId(), reqVO.getParentId(), reqVO.getName());
  66 + // 校验自己存在
  67 + validateDeptExists(updateReqVO.getId());
  68 + // 校验父部门的有效性
  69 + validateParentDept(updateReqVO.getId(), updateReqVO.getParentId());
  70 + // 校验部门名的唯一性
  71 + validateDeptNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
  72 +
66 73 // 更新部门
67   - DeptDO updateObj = DeptConvert.INSTANCE.convert(reqVO);
  74 + DeptDO updateObj = DeptConvert.INSTANCE.convert(updateReqVO);
68 75 deptMapper.updateById(updateObj);
69 76 }
70 77  
... ... @@ -82,15 +89,6 @@ public class DeptServiceImpl implements DeptService {
82 89 deptMapper.deleteById(id);
83 90 }
84 91  
85   - private void validateForCreateOrUpdate(Long id, Long parentId, String name) {
86   - // 校验自己存在
87   - validateDeptExists(id);
88   - // 校验父部门的有效性
89   - validateParentDept(id, parentId);
90   - // 校验部门名的唯一性
91   - validateDeptNameUnique(id, parentId, name);
92   - }
93   -
94 92 @VisibleForTesting
95 93 void validateDeptExists(Long id) {
96 94 if (id == null) {
... ... @@ -104,22 +102,36 @@ public class DeptServiceImpl implements DeptService {
104 102  
105 103 @VisibleForTesting
106 104 void validateParentDept(Long id, Long parentId) {
107   - if (parentId == null || DeptIdEnum.ROOT.getId().equals(parentId)) {
  105 + if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) {
108 106 return;
109 107 }
110   - // 不能设置自己为父部门
111   - if (parentId.equals(id)) {
  108 + // 1. 不能设置自己为父部门
  109 + if (Objects.equals(id, parentId)) {
112 110 throw exception(DEPT_PARENT_ERROR);
113 111 }
114   - // 父岗位不存在
115   - DeptDO dept = deptMapper.selectById(parentId);
116   - if (dept == null) {
  112 + // 2. 父部门不存在
  113 + DeptDO parentDept = deptMapper.selectById(parentId);
  114 + if (parentDept == null) {
117 115 throw exception(DEPT_PARENT_NOT_EXITS);
118 116 }
119   - // 父部门不能是原来的子部门
120   - List<DeptDO> children = getChildDeptList(id);
121   - if (children.stream().anyMatch(dept1 -> dept1.getId().equals(parentId))) {
122   - throw exception(DEPT_PARENT_IS_CHILD);
  117 + // 3. 递归校验父部门,如果父部门是自己的子部门,则报错,避免形成环路
  118 + if (id == null) { // id 为空,说明新增,不需要考虑环路
  119 + return;
  120 + }
  121 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  122 + // 3.1 校验环路
  123 + parentId = parentDept.getParentId();
  124 + if (Objects.equals(id, parentId)) {
  125 + throw exception(DEPT_PARENT_IS_CHILD);
  126 + }
  127 + // 3.2 继续递归下一级父部门
  128 + if (parentId == null || DeptDO.PARENT_ID_ROOT.equals(parentId)) {
  129 + break;
  130 + }
  131 + parentDept = deptMapper.selectById(parentId);
  132 + if (parentDept == null) {
  133 + break;
  134 + }
123 135 }
124 136 }
125 137  
... ... @@ -129,7 +141,7 @@ public class DeptServiceImpl implements DeptService {
129 141 if (dept == null) {
130 142 return;
131 143 }
132   - // 如果 id 为空,说明不用比较是否为相同 id 的岗位
  144 + // 如果 id 为空,说明不用比较是否为相同 id 的部门
133 145 if (id == null) {
134 146 throw exception(DEPT_NAME_DUPLICATE);
135 147 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostService.java
... ... @@ -2,10 +2,8 @@ package cn.iocoder.yudao.module.system.service.dept;
2 2  
3 3 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostCreateReqVO;
6   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostExportReqVO;
7 5 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
8   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostUpdateReqVO;
  6 +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
9 7 import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
10 8 import org.springframework.lang.Nullable;
11 9  
... ... @@ -24,17 +22,17 @@ public interface PostService {
24 22 /**
25 23 * 创建岗位
26 24 *
27   - * @param reqVO 岗位信息
  25 + * @param createReqVO 岗位信息
28 26 * @return 岗位编号
29 27 */
30   - Long createPost(PostCreateReqVO reqVO);
  28 + Long createPost(PostSaveReqVO createReqVO);
31 29  
32 30 /**
33 31 * 更新岗位
34 32 *
35   - * @param reqVO 岗位信息
  33 + * @param updateReqVO 岗位信息
36 34 */
37   - void updatePost(PostUpdateReqVO reqVO);
  35 + void updatePost(PostSaveReqVO updateReqVO);
38 36  
39 37 /**
40 38 * 删除岗位信息
... ... @@ -71,14 +69,6 @@ public interface PostService {
71 69 PageResult<PostDO> getPostPage(PostPageReqVO reqVO);
72 70  
73 71 /**
74   - * 获得岗位列表
75   - *
76   - * @param reqVO 查询条件
77   - * @return 部门列表
78   - */
79   - List<PostDO> getPostList(PostExportReqVO reqVO);
80   -
81   - /**
82 72 * 获得岗位信息
83 73 *
84 74 * @param id 岗位编号
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImpl.java
... ... @@ -3,11 +3,9 @@ package cn.iocoder.yudao.module.system.service.dept;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
5 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostCreateReqVO;
7   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostExportReqVO;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
8 7 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
9   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostUpdateReqVO;
10   -import cn.iocoder.yudao.module.system.convert.dept.PostConvert;
  8 +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
11 9 import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
12 10 import cn.iocoder.yudao.module.system.dal.mysql.dept.PostMapper;
13 11 import org.springframework.stereotype.Service;
... ... @@ -35,23 +33,23 @@ public class PostServiceImpl implements PostService {
35 33 private PostMapper postMapper;
36 34  
37 35 @Override
38   - public Long createPost(PostCreateReqVO reqVO) {
  36 + public Long createPost(PostSaveReqVO createReqVO) {
39 37 // 校验正确性
40   - validatePostForCreateOrUpdate(null, reqVO.getName(), reqVO.getCode());
  38 + validatePostForCreateOrUpdate(null, createReqVO.getName(), createReqVO.getCode());
41 39  
42 40 // 插入岗位
43   - PostDO post = PostConvert.INSTANCE.convert(reqVO);
  41 + PostDO post = BeanUtils.toBean(createReqVO, PostDO.class);
44 42 postMapper.insert(post);
45 43 return post.getId();
46 44 }
47 45  
48 46 @Override
49   - public void updatePost(PostUpdateReqVO reqVO) {
  47 + public void updatePost(PostSaveReqVO updateReqVO) {
50 48 // 校验正确性
51   - validatePostForCreateOrUpdate(reqVO.getId(), reqVO.getName(), reqVO.getCode());
  49 + validatePostForCreateOrUpdate(updateReqVO.getId(), updateReqVO.getName(), updateReqVO.getCode());
52 50  
53 51 // 更新岗位
54   - PostDO updateObj = PostConvert.INSTANCE.convert(reqVO);
  52 + PostDO updateObj = BeanUtils.toBean(updateReqVO, PostDO.class);
55 53 postMapper.updateById(updateObj);
56 54 }
57 55  
... ... @@ -120,11 +118,6 @@ public class PostServiceImpl implements PostService {
120 118 }
121 119  
122 120 @Override
123   - public List<PostDO> getPostList(PostExportReqVO reqVO) {
124   - return postMapper.selectList(reqVO);
125   - }
126   -
127   - @Override
128 121 public PostDO getPost(Long id) {
129 122 return postMapper.selectById(id);
130 123 }
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImplTest.java
... ... @@ -8,7 +8,6 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqV
8 8 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptUpdateReqVO;
9 9 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
10 10 import cn.iocoder.yudao.module.system.dal.mysql.dept.DeptMapper;
11   -import cn.iocoder.yudao.module.system.enums.dept.DeptIdEnum;
12 11 import org.junit.jupiter.api.Test;
13 12 import org.springframework.context.annotation.Import;
14 13  
... ... @@ -41,7 +40,7 @@ public class DeptServiceImplTest extends BaseDbUnitTest {
41 40 public void testCreateDept() {
42 41 // 准备参数
43 42 DeptCreateReqVO reqVO = randomPojo(DeptCreateReqVO.class, o -> {
44   - o.setParentId(DeptIdEnum.ROOT.getId());
  43 + o.setParentId(DeptDO.PARENT_ID_ROOT);
45 44 o.setStatus(randomCommonStatus());
46 45 });
47 46  
... ... @@ -62,7 +61,7 @@ public class DeptServiceImplTest extends BaseDbUnitTest {
62 61 // 准备参数
63 62 DeptUpdateReqVO reqVO = randomPojo(DeptUpdateReqVO.class, o -> {
64 63 // 设置更新的 ID
65   - o.setParentId(DeptIdEnum.ROOT.getId());
  64 + o.setParentId(DeptDO.PARENT_ID_ROOT);
66 65 o.setId(dbDeptDO.getId());
67 66 o.setStatus(randomCommonStatus());
68 67 });
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/dept/PostServiceImplTest.java
... ... @@ -4,10 +4,8 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
6 6 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
7   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostCreateReqVO;
8   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostExportReqVO;
9 7 import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostPageReqVO;
10   -import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostUpdateReqVO;
  8 +import cn.iocoder.yudao.module.system.controller.admin.dept.vo.post.PostSaveReqVO;
11 9 import cn.iocoder.yudao.module.system.dal.dataobject.dept.PostDO;
12 10 import cn.iocoder.yudao.module.system.dal.mysql.dept.PostMapper;
13 11 import org.junit.jupiter.api.Test;
... ... @@ -44,7 +42,7 @@ public class PostServiceImplTest extends BaseDbUnitTest {
44 42 @Test
45 43 public void testCreatePost_success() {
46 44 // 准备参数
47   - PostCreateReqVO reqVO = randomPojo(PostCreateReqVO.class,
  45 + PostSaveReqVO reqVO = randomPojo(PostSaveReqVO.class,
48 46 o -> o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()));
49 47 // 调用
50 48 Long postId = postService.createPost(reqVO);
... ... @@ -62,7 +60,7 @@ public class PostServiceImplTest extends BaseDbUnitTest {
62 60 PostDO postDO = randomPostDO();
63 61 postMapper.insert(postDO);// @Sql: 先插入出一条存在的数据
64 62 // 准备参数
65   - PostUpdateReqVO reqVO = randomPojo(PostUpdateReqVO.class, o -> {
  63 + PostSaveReqVO reqVO = randomPojo(PostSaveReqVO.class, o -> {
66 64 // 设置更新的 ID
67 65 o.setId(postDO.getId());
68 66 o.setStatus(randomEle(CommonStatusEnum.values()).getStatus());
... ... @@ -103,7 +101,7 @@ public class PostServiceImplTest extends BaseDbUnitTest {
103 101 PostDO postDO = randomPostDO();
104 102 postMapper.insert(postDO);// @Sql: 先插入出一条存在的数据
105 103 // 准备参数
106   - PostCreateReqVO reqVO = randomPojo(PostCreateReqVO.class,
  104 + PostSaveReqVO reqVO = randomPojo(PostSaveReqVO.class,
107 105 // 模拟 name 重复
108 106 o -> o.setName(postDO.getName()));
109 107 assertServiceException(() -> postService.createPost(reqVO), POST_NAME_DUPLICATE);
... ... @@ -118,7 +116,7 @@ public class PostServiceImplTest extends BaseDbUnitTest {
118 116 PostDO codePostDO = randomPostDO();
119 117 postMapper.insert(codePostDO);
120 118 // 准备参数
121   - PostUpdateReqVO reqVO = randomPojo(PostUpdateReqVO.class, o -> {
  119 + PostSaveReqVO reqVO = randomPojo(PostSaveReqVO.class, o -> {
122 120 // 设置更新的 ID
123 121 o.setId(postDO.getId());
124 122 // 模拟 code 重复
... ... @@ -155,30 +153,6 @@ public class PostServiceImplTest extends BaseDbUnitTest {
155 153 }
156 154  
157 155 @Test
158   - public void testGetPostList_export() {
159   - // mock 数据
160   - PostDO postDO = randomPojo(PostDO.class, o -> {
161   - o.setName("码仔");
162   - o.setStatus(CommonStatusEnum.ENABLE.getStatus());
163   - });
164   - postMapper.insert(postDO);
165   - // 测试 name 不匹配
166   - postMapper.insert(cloneIgnoreId(postDO, o -> o.setName("程序员")));
167   - // 测试 status 不匹配
168   - postMapper.insert(cloneIgnoreId(postDO, o -> o.setStatus(CommonStatusEnum.DISABLE.getStatus())));
169   - // 准备参数
170   - PostExportReqVO reqVO = new PostExportReqVO();
171   - reqVO.setName("码");
172   - reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
173   -
174   - // 调用
175   - List<PostDO> list = postService.getPostList(reqVO);
176   - // 断言
177   - assertEquals(1, list.size());
178   - assertPojoEquals(postDO, list.get(0));
179   - }
180   -
181   - @Test
182 156 public void testGetPostList() {
183 157 // mock 数据
184 158 PostDO postDO01 = randomPojo(PostDO.class, o -> o.setStatus(CommonStatusEnum.ENABLE.getStatus()));
... ...