diff --git a/.gitignore b/.gitignore
index 4c305b49..d885a769 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,4 +36,6 @@ build/
### Mac OS ###
.DS_Store
-/.idea/
\ No newline at end of file
+/.idea/
+/docker/minio/data/.minio.sys/
+/docker/minio/data/achobeta-recruitment/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..d8264b39
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,14 @@
+# 基础镜像
+FROM openjdk:21
+
+# 配置
+ENV PARAMS=""
+
+# 时区
+ENV TZ=PRC
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+# 添加应用
+ADD target/AchoBeta-Recruitment-1.0.jar /AchoBeta-Recruitment-1.0.jar
+
+ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /AchoBeta-Recruitment-1.0.jar $PARAMS"]
diff --git a/build.sh b/build.sh
index e273e82d..9bf5b932 100644
--- a/build.sh
+++ b/build.sh
@@ -1,5 +1,17 @@
-#!/bin/zsh
-# shellcheck disable=SC2164
+#!/usr/bin/env bash
+# Be sure your script exits whenever encounter errors
+
+echo "---------------------------------"
+echo "::: Welcome to AB-Recruitment :::"
+
+set -e
+# Be sure your charset is correct. eg: zh_CN.UTF-8
+export LC_ALL=en_US.UTF-8
+export LANG=en_US.UTF-8
+export LANGUAGE=en_US.UTF-8
+
mvn clean install package -Dmaven.test.skip=true
-docker-compose pull
-docker-compose up -d --build
\ No newline at end of file
+
+# 普通镜像构建,随系统版本构建 amd/arm
+
+docker-compose -f docker-compose.yml up -d
diff --git a/docker-compose.yml b/docker-compose.yml
index ff897245..d5b483d2 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,12 +1,180 @@
-version: '3'
+# 命令执行 docker-compose -f docker-compose.yml up -d
+version: '3.9'
services:
- recruitment:
- container_name: achobeta-recruitment #配置容器名
+ mysql:
+ image: mysql:5.7
+ container_name: mysql
+ command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
+ restart: always
+ environment:
+ TZ: Asia/Shanghai
+ MYSQL_ROOT_PASSWORD: achobeta666
+ MYSQL_USER: mms
+ MYSQL_PASSWORD: bitter-macaron
+ networks:
+ - my-network
+ depends_on:
+ - mysql-job-dbdata
+ ports:
+ - "13306:3306"
+ volumes:
+ - ./docker/mysql/db:/docker-entrypoint-initdb.d
+ healthcheck:
+ test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
+ interval: 5s
+ timeout: 10s
+ retries: 10
+ start_period: 15s
+
+ # 自动加载数据
+ mysql-job-dbdata:
+ image: alpine:3.18.2
+ container_name: mysql-job-dbdata
+ volumes:
+ - /var/lib/mysql
+
+ # phpmyadmin https://hub.docker.com/_/phpmyadmin
+ phpmyadmin:
+ image: phpmyadmin:5.2.1
+ container_name: phpmyadmin
+ hostname: phpmyadmin
+ ports:
+ - "8899:80"
+ environment:
+ - PMA_HOST=mysql
+ - PMA_PORT=3306
+ - MYSQL_ROOT_PASSWORD=achobeta666
+ depends_on:
+ mysql:
+ condition: service_healthy
+ networks:
+ - my-network
+
+ # Redis
+ redis:
+ image: redis:6.2
+ container_name: redis
+ restart: always
+ hostname: redis
+ privileged: true
+ ports:
+ - "6379:6379"
+ volumes:
+ - ./docker/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf
+ command: redis-server /usr/local/etc/redis/redis.conf
+ networks:
+ - my-network
+ healthcheck:
+ test: [ "CMD", "redis-cli", "ping" ]
+ interval: 10s
+ timeout: 5s
+ retries: 3
+
+ # RedisAdmin https://github.com/joeferner/redis-commander
+ # 账密 admin/admin
+ redis-admin:
+ image: spryker/redis-commander:0.8.0
+ container_name: redis-admin
+ hostname: redis-commander
+ restart: always
+ ports:
+ - "8081:8081"
+ environment:
+ - REDIS_HOSTS=local:redis:6379
+ - HTTP_USER=admin
+ - HTTP_PASSWORD=bitter-macaron
+ - LANG=C.UTF-8
+ - LANGUAGE=C.UTF-8
+ - LC_ALL=C.UTF-8
+ networks:
+ - my-network
+ depends_on:
+ redis:
+ condition: service_healthy
+
+ # rabbitmq
+ # 账密 admin/admin
+ # rabbitmq-plugins enable rabbitmq_management
+ rabbitmq:
+ image: rabbitmq:3.12.9
+ container_name: rabbitmq
+ restart: always
+ ports:
+ - "5672:5672"
+ - "15672:15672"
+ environment:
+ RABBITMQ_DEFAULT_USER: itcast
+ RABBITMQ_DEFAULT_PASS: 123321
+ command: rabbitmq-server
+ networks:
+ - my-network
+
+ # minio
+ minio:
+ image: minio/minio:RELEASE.2024-09-13T20-26-02Z
+ container_name: minio
+ hostname: minio
+ privileged: true
+ restart: always
+ environment:
+ # 账号
+ MINIO_ROOT_USER: mms
+ # 密码
+ MINIO_ROOT_PASSWORD: bitter-macaron
+ ports:
+ - "19005:19005"
+ - "9005:9005"
+ volumes:
+ - ./docker/minio/data:/data
+ command: server /data --console-address ":19005"
+ networks:
+ - my-network
+ healthcheck:
+ test: ["CMD", "curl", "-f", "http://localhost:9005/minio/health/live"]
+ interval: 30s
+ timeout: 20s
+ retries: 3
+
+ ab-recruitment-app:
+ container_name: ab-recruitment-app
build:
- context: .
- dockerfile: ./dockerfile #指定dockerFile文件
- image: java/achobeta-recruitment:1.0.0 # 指定镜像名
+ context: ./
+ dockerfile: Dockerfile
+ restart: always
ports:
- - "9001:9001" # 暴露端口
+ - "9001:19001"
+ environment:
+ - TZ=PRC
+ - SERVER_PORT=9001
+ - APP_CONFIG_API_VERSION=v1
+ - APP_CONFIG_CROSS_ORIGIN=*
+ - SPRING_DATASOURCE_USERNAME=mms
+ - SPRING_DATASOURCE_PASSWORD=bitter-macaron
+ - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/achobeta_recruitment?serverTimezone=UTC&characterEncoding=utf8&autoReconnect=true&serverTimezone=Asia/Shanghai
+ - SPRING_DATASOURCE_DRIVER_CLASS_NAME=com.mysql.jdbc.Driver
+ - SPRING_HIKARI_POOL_NAME=Retail_HikariCP
+ - REDIS_SDK_CONFIG_HOST=redis
+ - REDIS_SDK_CONFIG_PORT=6379
volumes:
- - ./logs:/logs # 创建容器数据卷
\ No newline at end of file
+ - ./log:/data/log
+ depends_on:
+ - redis
+ - rabbitmq
+ - mysql
+ - minio
+ links:
+ - redis
+ - rabbitmq
+ - mysql
+ - minio
+ networks:
+ - my-network
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "10m"
+ max-file: "3"
+
+networks:
+ my-network:
+ driver: bridge
\ No newline at end of file
diff --git a/docker/mysql/Dockerfile b/docker/mysql/Dockerfile
new file mode 100644
index 00000000..37d7b973
--- /dev/null
+++ b/docker/mysql/Dockerfile
@@ -0,0 +1,9 @@
+# 基础镜像
+FROM mysql:5.7
+
+# author
+MAINTAINER BanTanger
+
+# 执行sql脚本
+# `/docker-entrypoint-initdb.d/`是MySQL官方镜像中的一个特殊目录,用于存放初始化数据库的脚本文件。
+ADD ./db/*.sql /docker-entrypoint-initdb.d/
diff --git a/docker/mysql/db/recruitment-core.sql b/docker/mysql/db/recruitment-core.sql
new file mode 100644
index 00000000..f40e7965
--- /dev/null
+++ b/docker/mysql/db/recruitment-core.sql
@@ -0,0 +1,562 @@
+SET character_set_client = utf8;
+SET character_set_results = utf8;
+SET character_set_connection = utf8;
+
+drop database if exists achobeta_recruitment;
+create database achobeta_recruitment character set utf8mb4 collate utf8mb4_bin;
+use achobeta_recruitment;
+
+drop table if exists `user`;
+create table `user`
+(
+ `id` bigint primary key auto_increment comment '用户唯一 id',
+ `username` varchar(50) not null default '' comment '用户名',
+ `nickname` varchar(50) not null default '' comment '用户昵称',
+ `email` varchar(50) not null default '' comment '邮箱',
+ `phone_number` varchar(11) not null default '' comment '手机号码',
+ `password` varchar(100) not null default '' comment '密码',
+ `user_type` int not null default 1 comment '用户类型:1.普通用户 2. 管理员',
+ `avatar` bigint comment '头像地址',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_email`(`email` asc) using btree,
+ index `idx_phone`(`phone_number` asc) using btree,
+ unique `uni_username`(`username` asc) using btree
+) auto_increment = 10000 comment = '用户基本信息表';
+
+-- root 管理员,username: root; password: AchoBeta666
+insert into user(`username`, `nickname`, `password`, `user_type`)
+ values('root', 'root', '$2a$10$YPKp0kzLjnNrW5CgKuDdiuF4tZO0KXacmhy2KT7N9Zey49Cmi/rfu', 2);
+
+drop table if exists `member`;
+create table `member`
+(
+ `id` bigint primary key auto_increment comment '正式成员 id',
+ `resume_id` bigint not null comment '简历 id',
+ `manager_id` bigint unique not null comment '新开的管理员账号 id',
+ `parent_id` bigint not null comment '父管理员 id',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_resume_id`(`resume_id` asc) using btree,
+ unique index `uni_manager_id`(`manager_id` asc) using btree,
+ index `idx_parent_id`(`parent_id` asc) using btree
+) comment '正式成员表';
+
+drop table if exists `user_feedback`;
+create table `user_feedback`
+(
+ `id` bigint primary key auto_increment comment '反馈 id' ,
+ `user_id` bigint not null comment '用户id',
+ `batch_id` bigint not null comment '招新批次 id',
+ `message_id` bigint default null comment '处理结果的消息 id',
+ `title` varchar(256) default '' not null comment '反馈标题',
+ `content` text not null comment '反馈内容',
+ `attachment` bigint default null comment '附件链接',
+ `feedback_time` datetime default CURRENT_TIMESTAMP not null comment '反馈时间',
+ `is_handle` bit default b'0' not null comment '是否处理标记',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_user_id`(`user_id` asc) using btree,
+ index `idx_batch_id`(`batch_id` asc) using btree,
+ index `idx_message_id`(`message_id` asc) using btree
+) comment = '用户反馈表';
+
+drop table if exists `interview`;
+create table `interview`
+(
+ `id` bigint primary key auto_increment comment '面试 id',
+ `schedule_id` bigint unsigned not null comment '面试预约 id',
+ `paper_id` bigint default null comment '面试试卷 id',
+ `title` varchar(100) not null default '' comment '面试主题',
+ `description` text not null comment '面试说明',
+ `status` tinyint not null default 0 comment '是否开始(0未开始、1进行中、2已结束)',
+ `address` varchar(500) not null default '' comment '线下面试地址/显示面试会议链接',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_schedule_id`(`schedule_id` asc) using btree,
+ index `idx_paper_id`(`paper_id` asc) using btree
+) comment '面试表';
+
+drop table if exists `interview_comment`;
+create table `interview_comment`
+(
+ `id` bigint primary key auto_increment comment '面评 id',
+ `interview_id` bigint not null comment '面试 id',
+ `manager_id` bigint not null comment '管理员 id',
+ `content` text not null comment '评论内容',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_interview_id`(`interview_id` asc) using btree,
+ index `idx_manager_id`(`manager_id` asc) using btree
+) comment '面试评论表';
+
+drop table if exists `interview_question_score`;
+create table `interview_question_score`
+(
+ `id` bigint primary key auto_increment comment '面试题评分 id',
+ `interview_id` bigint not null comment '面试 id',
+ `question_id` bigint not null comment '问题 id',
+ `score` int not null comment '评分(0-10,-1为超纲)',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_interview_id`(`interview_id` asc) using btree,
+ index `idx_question_id`(`question_id` asc) using btree
+) comment '面试题评分关联表';
+
+drop table if exists `interview_schedule`;
+create table `interview_schedule`
+(
+ `id` bigint primary key auto_increment comment '面试预约 id',
+ `participation_id` bigint not null comment '用户的“活动参与” id',
+ `start_time` datetime not null comment '预约开始时间',
+ `end_time` datetime not null comment '预约结束时间',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_participation_id`(`participation_id` asc) using btree
+) comment '面试预约表';
+
+drop table if exists `interview_summary`;
+create table `interview_summary`
+(
+ `id` bigint primary key auto_increment comment '面试总结 id',
+ `interview_id` bigint not null comment '面试 id',
+ `basis` tinyint not null default 0 comment '基础理论知识掌握(0-5)',
+ `coding` tinyint not null default 0 comment '代码能力(0-5)',
+ `thinking` tinyint not null default 0 comment '思维能力(0-5)',
+ `express` tinyint not null default 0 comment '表达能力(0-5)',
+ `evaluate` varchar(500) not null default '' comment '面试总评',
+ `suggest` varchar(500) not null default '' comment '复习建议',
+ `playback` varchar(256) not null default '' comment '面试回放链接',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_interview_id`(`interview_id` asc) using btree
+) comment '面试总结表';
+
+drop table if exists `interviewer`;
+create table `interviewer`
+(
+ `id` bigint primary key auto_increment comment '面试官 id',
+ `manager_id` bigint not null comment '管理员 id',
+ `schedule_id` bigint not null comment '面试预约 id',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_manager_id`(`manager_id` asc) using btree,
+ index `idx_schedule_id`(`schedule_id` asc) using btree
+) comment '面试官表';
+
+drop table if exists `message`;
+create table `message`
+(
+ `id` bigint primary key auto_increment comment '消息 id',
+ `manager_id` bigint not null comment '发送消息的管理员 id',
+ `user_id` bigint not null comment '用户 id',
+ `tittle` varchar(256) not null default '' comment '消息标题',
+ `content` text not null comment '消息内容',
+ `send_time` datetime not null default current_timestamp comment '发送时间',
+ `attachment` bigint null default null comment '附件 url',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_manager_id`(`manager_id` asc) using btree,
+ index `idx_user_id`(`user_id` asc) using btree
+) comment = '消息表';
+
+drop table if exists `message_template`;
+create table `message_template`
+(
+ `id` bigint primary key auto_increment comment '模板消息 id',
+ `template_title` varchar(100) not null default '' comment '模板消息标题',
+ `template_content` text not null comment '模板消息内容',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间'
+) comment = '模板消息表';
+
+drop table if exists `library_paper_link`;
+create table `library_paper_link`
+(
+ `id` bigint primary key auto_increment comment 'id',
+ `lib_id` bigint not null comment '试卷库 id',
+ `paper_id` bigint not null comment '试卷 id',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_lp_id`(`lib_id` asc, `paper_id`) using btree
+) comment '试卷库-试卷关联表';
+
+drop table if exists `paper_question_link`;
+create table `paper_question_link`
+(
+ `id` bigint primary key auto_increment comment 'id',
+ `paper_id` bigint not null comment '试卷 id',
+ `question_id` bigint not null comment '问题 id',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index idx_pq_id(`paper_id` asc, `question_id`) using btree
+) comment '试卷-问题关联表';
+
+drop table if exists `question_paper`;
+create table `question_paper`
+(
+ `id` bigint primary key auto_increment comment '试卷 id',
+ `title` varchar(100) not null default '' comment '试卷标题',
+ `description` text not null comment '试卷说明',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间'
+) comment '试卷表';
+
+drop table if exists `question_paper_library`;
+create table `question_paper_library`
+(
+ `id` bigint primary key auto_increment comment '试卷库 id',
+ `lib_type` varchar(100) not null default '' comment '试卷库的类别,例如技术类的后端试卷,前端试卷;非技术的信息收集试卷;筛选的笔试试卷...',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_lib_type`(`lib_type` asc) using btree
+) comment '试卷库表';
+
+drop table if exists `library_question_link`;
+create table `library_question_link`
+(
+ `id` bigint primary key auto_increment comment 'id',
+ `lib_id` bigint not null comment '题库 id',
+ `question_id` bigint not null comment '问题 id',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_lq_id`(`lib_id` asc, `question_id`) using btree
+) comment '题库-问题关联表';
+
+drop table if exists `question`;
+create table `question`
+(
+ `id` bigint primary key auto_increment comment '问题 id',
+ `title` varchar(2048) not null default '' comment '问题标题',
+ `standard` text not null comment '问题标答',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间'
+) comment '问题表';
+
+drop table if exists `question_library`;
+create table `question_library`
+(
+ `id` bigint primary key auto_increment comment '题库 id',
+ `lib_type` varchar(100) not null default '' comment '题库的类别',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_lib_type`(`lib_type` asc) using btree
+) comment '题库表';
+
+drop table if exists `activity_participation`;
+create table `activity_participation`
+(
+ `id` bigint primary key auto_increment comment '“活动参与” id',
+ `stu_id` bigint not null comment '学生 id',
+ `act_id` bigint not null comment '活动 id',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_stu_id`(`stu_id` asc) using btree,
+ index `idx_act_id`(`act_id` asc) using btree
+) comment '“活动参与”表';
+
+drop table if exists `participation_period_link`;
+create table `participation_period_link`
+(
+ `id` bigint primary key auto_increment comment 'id',
+ `participation_id` bigint not null comment '“活动参与” id',
+ `period_id` bigint not null comment '时间段 id',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_pp_id`(`participation_id` asc, `period_id` asc) using btree
+) comment '“活动参与”-时间段关联表';
+
+drop table if exists `participation_question_link`;
+create table `participation_question_link`
+(
+ `id` bigint primary key auto_increment comment 'id',
+ `participation_id` bigint not null comment '“活动参与” id',
+ `question_id` bigint not null comment '问题 id',
+ `answer` text not null comment '回答',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_pq_id`(`participation_id` asc, `question_id` asc) using btree
+) comment '“活动参与”-问题关联表';
+
+drop table if exists `recruitment_activity`;
+create table `recruitment_activity`
+(
+ `id` bigint primary key auto_increment comment '招新活动 id',
+ `batch_id` bigint not null comment '招新批次 id',
+ `paper_id` bigint default null comment '试卷 id',
+ `title` varchar(100) not null default '' comment '活动标题',
+ `target` json not null comment '面向的人群',
+ `description` text not null comment '活动说明',
+ `deadline` datetime not null comment '截止时间',
+ `is_run` bit not null default b'0' comment '是否启动',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_batch_id`(`batch_id` asc) using btree,
+ index `idx_paper_id`(`paper_id` asc) using btree
+) comment '招新活动表';
+
+drop table if exists `recruitment_batch`;
+create table `recruitment_batch`
+(
+ `id` bigint primary key auto_increment comment '招新批次 id',
+ `batch` int not null comment 'AchoBeta 届数',
+ `title` varchar(100) not null default '' comment '招新标题',
+ `deadline` datetime not null comment '截止时间',
+ `is_run` bit not null default b'0' comment '是否启动',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_batch`(`batch` asc) using btree
+) comment '招新批次表';
+
+drop table if exists `time_period`;
+create table `time_period`
+(
+ `id` bigint primary key auto_increment comment '时间段 id',
+ `act_id` bigint not null comment '招新活动 id',
+ `start_time` datetime not null comment '开始时间',
+ `end_time` datetime not null comment '结束时间',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_act_id`(`act_id` asc) using btree
+) comment '时间段表';
+
+drop table if exists `digital_resource`;
+create table `digital_resource`
+(
+ `id` bigint primary key auto_increment comment '资源 id',
+ `code` bigint unique not null comment '资源码',
+ `user_id` bigint not null comment '上传文件的用户 id',
+ `access_level` int not null default 2 comment '访问权限',
+ `original_name` varchar(100) not null comment '上传时的文件名',
+ `file_name` varchar(256) not null comment '在对象存储服务中存储的对象名',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ unique index `uni_code`(`code` asc) using btree,
+ index `idx_user_id`(`user_id` asc) using btree
+) comment '资源表';
+
+drop table if exists `feishu_resource`;
+create table `feishu_resource`
+(
+ `id` bigint primary key auto_increment comment '飞书资源 id',
+ `ticket` varchar(50) unique not null comment '任务 ID',
+ `original_name` varchar(100) not null comment '上传时的文件名',
+ `token` varchar(50) not null default '' comment '导入云文档的 token',
+ `type` varchar(20) not null default '' comment '导入的在线云文档类型',
+ `url` varchar(200) not null default '' comment '导入云文档的 URL',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ unique index `uni_ticket`(`ticket`) using btree
+) comment '飞书资源表';
+
+drop table if exists `short_link`;
+create table `short_link`
+(
+ `id` bigint primary key auto_increment comment '短链接编号',
+ `origin_url` varchar(512) default '' comment '原链接',
+ `short_code` char(6) unique default '' comment '短链code',
+ `is_used` bit default b'0' comment '是否使用过',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- 索引
+ index `idx_short_code`(`short_code` asc) using btree
+) comment '长短链关系表';
+
+drop table if exists `resume_status_process`;
+create table `resume_status_process`
+(
+ `id` bigint primary key auto_increment comment 'id',
+ `resume_id` bigint not null comment '简历 id',
+ `resume_status` int not null comment '简历状态',
+ `resume_event` int not null comment '简历事件',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- 索引
+ index `idx_resume_id`(`resume_id` asc) using btree
+) comment '招新简历状态过程表';
+
+drop table if exists `stu_attachment`;
+create table `stu_attachment`
+(
+ `id` bigint primary key auto_increment comment 'id',
+ `resume_id` bigint not null comment '学生表主键 id',
+ `filename` varchar(256) not null default '' comment '附件名',
+ `attachment` bigint not null comment '附件资源码',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_resume_id`(`resume_id` asc) using btree
+) comment = '学生附件表';
+
+-- 简历状态 comment 说明
+-- 范围:0~16,简历状态{
+-- 0-草稿
+-- 1-待筛选
+-- 2-筛选不通过
+--
+-- 3-待安排初试
+-- 4-待初试
+-- 5-初试通过(仅当初试为最后一个流程时显示)
+-- 6-初试不通过(仅当初试为最后一个流程时显示)
+--
+-- 7-待安排复试
+-- 8-待复试
+-- 9-复试通过(仅当复试为最后一个流程时显示)
+-- 10-复试不通过(仅当复试为最后一个流程时显示)
+--
+-- 11-待安排终试
+-- 12-待终试
+-- 13-终试通过(仅当复试为最后一个流程时显示)
+-- 14-终试不通过(仅当复试为最后一个流程时显示)
+--
+-- 15-待处理(反馈异常/或管理员主动设置为该状态)
+-- 16-挂起(管理员可以主动设置该状态)
+-- }
+-- ----------------------------
+-- 创建学生简历表
+drop table if exists `stu_resume`;
+create table `stu_resume`
+(
+ `id` bigint primary key auto_increment comment 'id',
+ `user_id` bigint not null comment '用户 id',
+ `batch_id` bigint not null comment '招新批次 id',
+ `student_id` varchar(13) not null default '' comment '学号',
+ `name` varchar(10) not null default '' comment '姓名',
+ `gender` tinyint not null default 0 comment '性别',
+ `grade` int not null comment '年级',
+ `major` varchar(20) not null default '' comment '专业',
+ `class` varchar(30) not null default '' comment '班级',
+ `email` varchar(50) not null default '' comment '邮箱',
+ `phone_number` varchar(11) not null default '' comment '手机号码',
+ `reason` text not null comment '加入 achobeta 的理由',
+ `introduce` text not null comment '个人介绍(自我认知)',
+ `experience` text not null comment '个人经历(项目经历、职业规划等)',
+ `awards` text not null comment '获奖经历',
+ `image` bigint not null comment '照片',
+ `remark` varchar(500) not null default '' comment '备注',
+ `status` int not null default 1 comment '简历状态,范围:0~16',
+ `submit_count` int not null default 0 comment '提交次数',
+ -- common column
+ `version` int not null default 0 comment '乐观锁',
+ `is_deleted` bit not null default b'0' comment '伪删除标记',
+ `create_time` datetime not null default current_timestamp comment '创建时间',
+ `update_time` datetime not null default current_timestamp on update current_timestamp comment '更新时间',
+ -- index
+ index `idx_student_id` (`student_id` asc) using btree,
+ index `idx_email` (`email` asc) using btree,
+ index `idx_user_id` (`user_id` asc) using btree,
+ index `idx_batch_id` (`batch_id` asc) using btree,
+ index `idx_class` (`class` asc) using btree,
+ index `idx_major` (`major` asc) using btree,
+ index `idx_name` (`name` asc) using btree
+) comment = '学生简历表';
diff --git a/docker/redis/Dockerfile b/docker/redis/Dockerfile
new file mode 100644
index 00000000..845d6315
--- /dev/null
+++ b/docker/redis/Dockerfile
@@ -0,0 +1,14 @@
+# 基础镜像
+FROM redis:6.0.8
+# author
+MAINTAINER BanTanger
+
+EXPOSE 6379
+# 挂载目录
+VOLUME /home/order/redis
+# 创建目录
+RUN mkdir -p /home/order/redis
+# 指定路径
+WORKDIR /home/order/redis
+# 复制conf文件到路径
+COPY ./conf/redis.conf /home/order/redis/redis.conf
diff --git a/docker/redis/conf/redis.conf b/docker/redis/conf/redis.conf
new file mode 100644
index 00000000..8fe64b4e
--- /dev/null
+++ b/docker/redis/conf/redis.conf
@@ -0,0 +1,5 @@
+bind 0.0.0.0
+requirepass bitter-macaron
+protected-mode no
+appendonly yes
+daemonize no
diff --git a/dockerfile b/dockerfile
deleted file mode 100644
index 433514a0..00000000
--- a/dockerfile
+++ /dev/null
@@ -1,10 +0,0 @@
-# 以jdk8为基础镜像
-FROM openjdk:21
-# 描述
-LABEL description="AchoBeta Recruitment"
-# 暴露接口
-EXPOSE 9001
-# 将主机中的jar包添加到镜像中
-ADD target/AchoBeta-Recruitment-1.0.jar AchoBeta-Recruitment-1.0.jar
-# 运行jar包
-ENTRYPOINT ["java", "-jar","AchoBeta-Recruitment-1.0.jar"]
\ No newline at end of file
diff --git a/src/main/java/com/achobeta/common/annotation/IsAccessible.java b/src/main/java/com/achobeta/common/annotation/Accessible.java
similarity index 80%
rename from src/main/java/com/achobeta/common/annotation/IsAccessible.java
rename to src/main/java/com/achobeta/common/annotation/Accessible.java
index c8321048..cd3a03a7 100644
--- a/src/main/java/com/achobeta/common/annotation/IsAccessible.java
+++ b/src/main/java/com/achobeta/common/annotation/Accessible.java
@@ -1,6 +1,6 @@
package com.achobeta.common.annotation;
-import com.achobeta.common.annotation.handler.IsAccessibleValidator;
+import com.achobeta.common.annotation.handler.AccessibleValidator;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
@@ -14,10 +14,10 @@
* Time: 23:50
*/
@Documented
-@Constraint(validatedBy = {IsAccessibleValidator.class})
+@Constraint(validatedBy = {AccessibleValidator.class})
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
-public @interface IsAccessible {
+public @interface Accessible {
String message() default "url 无法访问"; // 默认消息
diff --git a/src/main/java/com/achobeta/common/annotation/HttpUrl.java b/src/main/java/com/achobeta/common/annotation/HttpUrl.java
new file mode 100644
index 00000000..036e06a2
--- /dev/null
+++ b/src/main/java/com/achobeta/common/annotation/HttpUrl.java
@@ -0,0 +1,27 @@
+package com.achobeta.common.annotation;
+
+import com.achobeta.common.annotation.handler.HttpUrlValidator;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-19
+ * Time: 11:35
+ */
+@Documented
+@Constraint(validatedBy = {HttpUrlValidator.class})
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HttpUrl {
+
+ String message() default "链接非法"; // 默认消息
+
+ Class>[] groups() default {}; // 分组校验
+
+ Class extends Payload>[] payload() default {}; // 负载信息
+}
diff --git a/src/main/java/com/achobeta/common/annotation/Intercept.java b/src/main/java/com/achobeta/common/annotation/Intercept.java
index 0b666922..5b367db9 100644
--- a/src/main/java/com/achobeta/common/annotation/Intercept.java
+++ b/src/main/java/com/achobeta/common/annotation/Intercept.java
@@ -27,6 +27,4 @@
boolean ignore() default false;
- boolean log() default false;
-
}
diff --git a/src/main/java/com/achobeta/common/annotation/MobilePhone.java b/src/main/java/com/achobeta/common/annotation/MobilePhone.java
new file mode 100644
index 00000000..5cf8ac13
--- /dev/null
+++ b/src/main/java/com/achobeta/common/annotation/MobilePhone.java
@@ -0,0 +1,27 @@
+package com.achobeta.common.annotation;
+
+import com.achobeta.common.annotation.handler.MobilePhoneValidator;
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+
+import java.lang.annotation.*;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-17
+ * Time: 21:59
+ */
+@Documented
+@Constraint(validatedBy = {MobilePhoneValidator.class})
+@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MobilePhone {
+
+ String message() default "手机号非法"; // 默认消息
+
+ Class>[] groups() default {}; // 分组校验
+
+ Class extends Payload>[] payload() default {}; // 负载信息
+}
diff --git a/src/main/java/com/achobeta/common/annotation/handler/IsAccessibleValidator.java b/src/main/java/com/achobeta/common/annotation/handler/AccessibleValidator.java
similarity index 72%
rename from src/main/java/com/achobeta/common/annotation/handler/IsAccessibleValidator.java
rename to src/main/java/com/achobeta/common/annotation/handler/AccessibleValidator.java
index 485a4f68..7575e732 100644
--- a/src/main/java/com/achobeta/common/annotation/handler/IsAccessibleValidator.java
+++ b/src/main/java/com/achobeta/common/annotation/handler/AccessibleValidator.java
@@ -1,16 +1,15 @@
package com.achobeta.common.annotation.handler;
-import com.achobeta.common.annotation.IsAccessible;
+import com.achobeta.common.annotation.Accessible;
import com.achobeta.util.HttpRequestUtil;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.extern.slf4j.Slf4j;
-import java.io.IOException;
import java.util.Optional;
@Slf4j
-public class IsAccessibleValidator implements ConstraintValidator {
+public class AccessibleValidator implements ConstraintValidator {
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
@@ -19,8 +18,7 @@ public boolean isValid(String s, ConstraintValidatorContext constraintValidatorC
.map(url -> {
try {
return HttpRequestUtil.isAccessible(url);
- } catch (IOException e) {
- // 重定向次数过多也判定为无法访问
+ } catch (Exception e) {
log.warn(e.getMessage());
return Boolean.FALSE;
}
diff --git a/src/main/java/com/achobeta/common/annotation/handler/HttpUrlValidator.java b/src/main/java/com/achobeta/common/annotation/handler/HttpUrlValidator.java
new file mode 100644
index 00000000..e5f10de3
--- /dev/null
+++ b/src/main/java/com/achobeta/common/annotation/handler/HttpUrlValidator.java
@@ -0,0 +1,25 @@
+package com.achobeta.common.annotation.handler;
+
+import com.achobeta.common.annotation.HttpUrl;
+import com.achobeta.util.HttpRequestUtil;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+
+import java.util.Optional;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-19
+ * Time: 11:35
+ */
+public class HttpUrlValidator implements ConstraintValidator {
+
+ @Override
+ public boolean isValid(String url, ConstraintValidatorContext constraintValidatorContext) {
+ return Optional.ofNullable(url)
+ .map(s -> HttpRequestUtil.HTTP_URL_PATTERN.matcher(s).matches())
+ .orElse(Boolean.TRUE);
+ }
+}
diff --git a/src/main/java/com/achobeta/common/annotation/handler/InterceptHelper.java b/src/main/java/com/achobeta/common/annotation/handler/InterceptHelper.java
index a2288b90..f2a47cb5 100644
--- a/src/main/java/com/achobeta/common/annotation/handler/InterceptHelper.java
+++ b/src/main/java/com/achobeta/common/annotation/handler/InterceptHelper.java
@@ -39,14 +39,6 @@ public static boolean isIgnore(Method targetMethod) {
return isIgnore(getIntercept(targetMethod));
}
- public static boolean shouldPrintLog(Intercept intercept) {
- return Objects.isNull(intercept) || intercept.log();
- }
-
- public static boolean shouldPrintLog(Method targetMethod) {
- return shouldPrintLog(getIntercept(targetMethod));
- }
-
public static boolean isValid(Intercept intercept, UserTypeEnum role) {
// permit 中没有 role 就会抛异常
return Arrays.stream(intercept.permit())
diff --git a/src/main/java/com/achobeta/common/annotation/handler/MobilePhoneValidator.java b/src/main/java/com/achobeta/common/annotation/handler/MobilePhoneValidator.java
new file mode 100644
index 00000000..94bd15f5
--- /dev/null
+++ b/src/main/java/com/achobeta/common/annotation/handler/MobilePhoneValidator.java
@@ -0,0 +1,28 @@
+package com.achobeta.common.annotation.handler;
+
+import com.achobeta.common.annotation.MobilePhone;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+
+import java.util.Optional;
+import java.util.regex.Pattern;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-17
+ * Time: 22:00
+ */
+public class MobilePhoneValidator implements ConstraintValidator {
+
+ private final static Pattern MOBILE_PHONE_PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
+
+ @Override
+ public boolean isValid(String phone, ConstraintValidatorContext constraintValidatorContext) {
+ return Optional.ofNullable(phone)
+ .map(s -> MOBILE_PHONE_PATTERN.matcher(s).matches())
+ .orElse(Boolean.TRUE);
+ }
+
+}
diff --git a/src/main/java/com/achobeta/domain/evaluate/handler/ext/RemovePaperIQScoreHandler.java b/src/main/java/com/achobeta/domain/evaluate/handler/ext/RemovePaperIQScoreHandler.java
index 2255eccc..94360315 100644
--- a/src/main/java/com/achobeta/domain/evaluate/handler/ext/RemovePaperIQScoreHandler.java
+++ b/src/main/java/com/achobeta/domain/evaluate/handler/ext/RemovePaperIQScoreHandler.java
@@ -34,18 +34,17 @@ public void handle(Long paperId) {
.stream()
.map(Interview::getId)
.toList();
- if(CollectionUtils.isEmpty(interviewIds)) {
- return;
+ if(!CollectionUtils.isEmpty(interviewIds)) {
+ // 将面试试卷设置为空
+ interviewService.lambdaUpdate()
+ .in(Interview::getId, interviewIds)
+ .set(Interview::getPaperId, null)
+ .update();
+ // 删除对应的评分
+ interviewQuestionScoreService.lambdaUpdate()
+ .in(InterviewQuestionScore::getInterviewId, interviewIds)
+ .remove();
}
- // 将面试试卷设置为空
- interviewService.lambdaUpdate()
- .in(Interview::getId, interviewIds)
- .set(Interview::getPaperId, null)
- .update();
- // 删除对应的评分
- interviewQuestionScoreService.lambdaUpdate()
- .in(InterviewQuestionScore::getInterviewId, interviewIds)
- .remove();
// 执行下一个
super.doNextHandler(paperId);
}
diff --git a/src/main/java/com/achobeta/domain/evaluate/handler/ext/RemoveQuestionFromPaperIQSHandler.java b/src/main/java/com/achobeta/domain/evaluate/handler/ext/RemoveQuestionFromPaperIQSHandler.java
index 85502700..7e0590e4 100644
--- a/src/main/java/com/achobeta/domain/evaluate/handler/ext/RemoveQuestionFromPaperIQSHandler.java
+++ b/src/main/java/com/achobeta/domain/evaluate/handler/ext/RemoveQuestionFromPaperIQSHandler.java
@@ -7,6 +7,7 @@
import com.achobeta.domain.paper.handler.RemoveQuestionFromPaperHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
import java.util.List;
@@ -34,10 +35,12 @@ public void handle(Long paperId, List questionIds) {
.map(Interview::getId)
.toList();
// 删除对应的评分
- interviewQuestionScoreService.lambdaUpdate()
- .in(InterviewQuestionScore::getInterviewId, interviewIds)
- .in(InterviewQuestionScore::getQuestionId, questionIds)
- .remove();
+ if(!CollectionUtils.isEmpty(interviewIds) && !CollectionUtils.isEmpty(questionIds)) {
+ interviewQuestionScoreService.lambdaUpdate()
+ .in(InterviewQuestionScore::getInterviewId, interviewIds)
+ .in(InterviewQuestionScore::getQuestionId, questionIds)
+ .remove();
+ }
// 执行下一个
super.doNextHandler(paperId, questionIds);
}
diff --git a/src/main/java/com/achobeta/domain/evaluate/machine/events/internal/InterviewExperienceHelper.java b/src/main/java/com/achobeta/domain/evaluate/machine/events/internal/InterviewExperienceHelper.java
index 0812f0ba..bf9beb24 100644
--- a/src/main/java/com/achobeta/domain/evaluate/machine/events/internal/InterviewExperienceHelper.java
+++ b/src/main/java/com/achobeta/domain/evaluate/machine/events/internal/InterviewExperienceHelper.java
@@ -91,7 +91,6 @@ public Action getPerformActio
InterviewExperienceTemplateInner inner = InterviewExperienceTemplateInner.builder()
.title(question.getTitle())
.score(question.getScore())
- .average(question.getAverage())
.standard(target)
.build();
replaceResourceList.add(new ReplaceResource(target, question.getStandard()));
diff --git a/src/main/java/com/achobeta/domain/evaluate/model/dto/InterviewSummaryDTO.java b/src/main/java/com/achobeta/domain/evaluate/model/dto/InterviewSummaryDTO.java
index c2793e2f..083f6dd8 100644
--- a/src/main/java/com/achobeta/domain/evaluate/model/dto/InterviewSummaryDTO.java
+++ b/src/main/java/com/achobeta/domain/evaluate/model/dto/InterviewSummaryDTO.java
@@ -1,7 +1,7 @@
package com.achobeta.domain.evaluate.model.dto;
+import com.achobeta.common.annotation.Accessible;
import com.achobeta.common.annotation.IntRange;
-import com.achobeta.common.annotation.IsAccessible;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@@ -44,7 +44,7 @@ public class InterviewSummaryDTO {
private String suggest;
// @NotBlank(message = "回放不能为空")
- @IsAccessible(message = "回放链接不可访问")
+ @Accessible
private String playback;
}
diff --git a/src/main/java/com/achobeta/domain/evaluate/model/vo/InterviewExperienceTemplateInner.java b/src/main/java/com/achobeta/domain/evaluate/model/vo/InterviewExperienceTemplateInner.java
index 08903b4f..19945649 100644
--- a/src/main/java/com/achobeta/domain/evaluate/model/vo/InterviewExperienceTemplateInner.java
+++ b/src/main/java/com/achobeta/domain/evaluate/model/vo/InterviewExperienceTemplateInner.java
@@ -22,8 +22,6 @@ public class InterviewExperienceTemplateInner {
private Integer score;
- private Double average;
-
private String standard;
}
diff --git a/src/main/java/com/achobeta/domain/evaluate/model/vo/InterviewRankVO.java b/src/main/java/com/achobeta/domain/evaluate/model/vo/InterviewRankVO.java
index f7a9f8bc..6975f419 100644
--- a/src/main/java/com/achobeta/domain/evaluate/model/vo/InterviewRankVO.java
+++ b/src/main/java/com/achobeta/domain/evaluate/model/vo/InterviewRankVO.java
@@ -14,16 +14,16 @@
@Data
public class InterviewRankVO {
- private Long summaryId;
-
- private Integer average;
-
private Long interviewId;
private String title;
private InterviewStatus status;
+ private Long summaryId;
+
+ private Integer sum;
+
private SimpleStudentVO simpleStudentVO;
}
diff --git a/src/main/java/com/achobeta/domain/evaluate/service/impl/InterviewQuestionScoreServiceImpl.java b/src/main/java/com/achobeta/domain/evaluate/service/impl/InterviewQuestionScoreServiceImpl.java
index 58214554..4e314f25 100644
--- a/src/main/java/com/achobeta/domain/evaluate/service/impl/InterviewQuestionScoreServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/evaluate/service/impl/InterviewQuestionScoreServiceImpl.java
@@ -14,9 +14,11 @@
import com.achobeta.domain.question.model.vo.QuestionVO;
import com.achobeta.redis.lock.RedisLock;
import com.achobeta.redis.lock.strategy.SimpleLockStrategy;
+import com.achobeta.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
@@ -67,9 +69,11 @@ public List getQuestionScoresByInterviewId(Long intervie
@Override
public List getAverageQuestions(List questionIds) {
- return Optional.ofNullable(questionIds)
- .map(ids -> interviewQuestionScoreMapper.getAverageQuestions(questionIds))
- .orElseGet(ArrayList::new);
+ questionIds = ObjectUtil.distinctNonNullStream(questionIds).toList();
+ if(CollectionUtils.isEmpty(questionIds)) {
+ return new ArrayList<>();
+ }
+ return interviewQuestionScoreMapper.getAverageQuestions(questionIds);
}
@Override
diff --git a/src/main/java/com/achobeta/domain/evaluate/service/impl/InterviewSummaryServiceImpl.java b/src/main/java/com/achobeta/domain/evaluate/service/impl/InterviewSummaryServiceImpl.java
index fd4a3656..ffe7bd09 100644
--- a/src/main/java/com/achobeta/domain/evaluate/service/impl/InterviewSummaryServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/evaluate/service/impl/InterviewSummaryServiceImpl.java
@@ -65,6 +65,8 @@ public void summaryInterview(InterviewSummaryDTO interviewSummaryDTO) {
getInterviewSummaryByInterviewId(interviewId).map(InterviewSummary::getId).ifPresentOrElse(summaryId -> {
this.lambdaUpdate()
.eq(InterviewSummary::getId, summaryId)
+ .set(InterviewSummary::getPlayback, Optional.ofNullable(interviewSummary.getPlayback()).orElse(""))
+ .set(InterviewSummary::getSuggest, Optional.ofNullable(interviewSummary.getSuggest()).orElse(""))
.update(interviewSummary);
}, () -> {
this.save(interviewSummary);
diff --git a/src/main/java/com/achobeta/domain/feishu/service/impl/FeishuServiceImpl.java b/src/main/java/com/achobeta/domain/feishu/service/impl/FeishuServiceImpl.java
index b70fcaca..0bbd10e8 100644
--- a/src/main/java/com/achobeta/domain/feishu/service/impl/FeishuServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/feishu/service/impl/FeishuServiceImpl.java
@@ -7,7 +7,7 @@
import com.achobeta.feishu.config.ResourceProperties;
import com.achobeta.feishu.constants.ObjectType;
import com.achobeta.feishu.request.FeishuRequestEngine;
-import com.achobeta.feishu.token.FeishuTenantAccessToken;
+import com.achobeta.feishu.token.FeishuTenantSession;
import com.achobeta.util.GsonUtil;
import com.achobeta.util.MediaUtil;
import com.achobeta.util.TimeUtil;
@@ -57,7 +57,7 @@ public class FeishuServiceImpl implements FeishuService, InitializingBean {
private final FeishuAppConfig feishuAppConfig;
- private final FeishuTenantAccessToken feishuTenantAccessToken;
+ private final FeishuTenantSession feishuTenantSession;
private final FeishuRequestEngine feishuRequestEngine;
@@ -86,7 +86,7 @@ public BatchGetIdUserRespBody batchGetUserId(BatchGetIdUserReqBody batchGetIdUse
// } catch (Exception e) {
// throw new GlobalServiceException(e.getMessage());
// }
- String token = feishuTenantAccessToken.getToken();
+ String token = feishuTenantSession.getToken();
return feishuRequestEngine.jsonRequest(
GET_USER_ID,
batchGetIdUserReqBody,
@@ -133,7 +133,7 @@ public ApplyReserveRespBody reserveApply(ApplyReserveReqBody applyReserveReqBody
// } catch (Exception e) {
// throw new GlobalServiceException(e.getMessage());
// }
- String token = feishuTenantAccessToken.getToken();
+ String token = feishuTenantSession.getToken();
return feishuRequestEngine.jsonRequest(
RESERVE_APPLY,
applyReserveReqBody,
@@ -145,10 +145,15 @@ public ApplyReserveRespBody reserveApply(ApplyReserveReqBody applyReserveReqBody
@Override
public ApplyReserveRespBody reserveApplyBriefly(String ownerId, Long endTime, String topic) {
+ // 这里预约的会议不会出现在日历里
+ // 其中,是否自动录制(云录制,无法自动本地录制),不会根据飞书管理后台的全局配置中的是否自动录制,在飞书网页/软件申请的会议根据的才会用到这个全局配置
+ // 而我们这次的请求参数若不设置,默认为 false(局部优先),设置为 true 后,若允许云录制会议有若的时候就会自动录制
ApplyReserveReqBody reserveReqBody = ApplyReserveReqBody.newBuilder()
.endTime(String.valueOf(TimeUtil.millisToSecond(endTime)))
.ownerId(ownerId)
- .meetingSettings(ReserveMeetingSetting.newBuilder().topic(topic).meetingInitialType(GROUP_MEETING).build())
+ .meetingSettings(ReserveMeetingSetting.newBuilder().topic(topic)
+// .autoRecord(Boolean.TRUE)
+ .meetingInitialType(GROUP_MEETING).build())
.build();
return reserveApply(reserveReqBody);
}
@@ -228,7 +233,7 @@ public CreateImportTaskRespBody importTask(ImportTask importTask) {
// } catch (Exception e) {
// throw new GlobalServiceException(e.getMessage());
// }
- String token = feishuTenantAccessToken.getToken();
+ String token = feishuTenantSession.getToken();
return feishuRequestEngine.jsonRequest(
IMPORT_TASK,
importTask,
@@ -264,7 +269,7 @@ public GetImportTaskRespBody getImportTask(String ticket) {
// } catch (Exception e) {
// throw new GlobalServiceException(e.getMessage());
// }
- String token = feishuTenantAccessToken.getToken();
+ String token = feishuTenantSession.getToken();
return feishuRequestEngine.jsonRequest(
GET_IMPORT_TASK,
null,
diff --git a/src/main/java/com/achobeta/domain/interview/controller/InterviewController.java b/src/main/java/com/achobeta/domain/interview/controller/InterviewController.java
index bced860e..4e0a4337 100644
--- a/src/main/java/com/achobeta/domain/interview/controller/InterviewController.java
+++ b/src/main/java/com/achobeta/domain/interview/controller/InterviewController.java
@@ -34,9 +34,6 @@
import java.util.Objects;
import java.util.Optional;
-import static com.achobeta.domain.interview.enums.InterviewStatus.ENDED;
-import static com.achobeta.domain.interview.enums.InterviewStatus.NOT_STARTED;
-
/**
* Created With Intellij IDEA
* Description:
@@ -70,8 +67,6 @@ public SystemJsonResponse createInterview(@Valid @RequestBody InterviewCreateDTO
@PostMapping("/update")
public SystemJsonResponse updateInterview(@Valid @RequestBody InterviewUpdateDTO interviewUpdateDTO) {
- // 未开始才能修改
- interviewService.checkInterviewStatus(interviewUpdateDTO.getInterviewId(), List.of(NOT_STARTED, ENDED));
// 更新
interviewService.updateInterview(interviewUpdateDTO);
return SystemJsonResponse.SYSTEM_SUCCESS();
@@ -117,14 +112,12 @@ public SystemJsonResponse setPaperForInterview(@Valid @RequestBody InterviewPape
// 检查
Long interviewId = interviewPaperDTO.getInterviewId();
Interview interview = interviewService.checkAndGetInterviewExists(interviewId);
- // 检查面试是否未开始
- interview.getStatus().check(List.of(NOT_STARTED, ENDED));
Long paperId = interviewPaperDTO.getPaperId();
if(!Objects.equals(interview.getPaperId(), paperId)) {
// 检查试卷是否存在
questionPaperService.checkPaperExists(paperId);
// 设置试卷
- interviewService.setPaperForInterview(interviewId, paperId);
+ interviewService.setPaperForInterview(interview, paperId);
}
return SystemJsonResponse.SYSTEM_SUCCESS();
}
@@ -132,7 +125,7 @@ public SystemJsonResponse setPaperForInterview(@Valid @RequestBody InterviewPape
@PostMapping("/list/manager/all")
public SystemJsonResponse managerGetAllInterviewList(@Valid @RequestBody(required = false) InterviewConditionDTO interviewConditionDTO) {
// 查询
- List interviewVOList = interviewService.managerGetInterviewList(null, InterviewConditionDTO.of(interviewConditionDTO));
+ List interviewVOList = interviewService.managerGetInterviewList(null, InterviewConditionDTO.of(interviewConditionDTO));
return SystemJsonResponse.SYSTEM_SUCCESS(interviewVOList);
}
@@ -154,7 +147,7 @@ public SystemJsonResponse managerGetOwnInterviewList(@Valid @RequestBody(require
// 获取当前管理员 id
Long managerId = BaseContext.getCurrentUser().getUserId();
// 查询
- List interviewVOList = interviewService.managerGetInterviewList(managerId, InterviewConditionDTO.of(interviewConditionDTO));
+ List interviewVOList = interviewService.managerGetInterviewList(managerId, InterviewConditionDTO.of(interviewConditionDTO));
return SystemJsonResponse.SYSTEM_SUCCESS(interviewVOList);
}
diff --git a/src/main/java/com/achobeta/domain/interview/model/converter/InterviewConverter.java b/src/main/java/com/achobeta/domain/interview/model/converter/InterviewConverter.java
index d16ab1bb..4ba5d93d 100644
--- a/src/main/java/com/achobeta/domain/interview/model/converter/InterviewConverter.java
+++ b/src/main/java/com/achobeta/domain/interview/model/converter/InterviewConverter.java
@@ -39,6 +39,6 @@ public interface InterviewConverter {
InterviewReserveVO feishuReserveToInterviewReserveVO(Reserve reserve);
- List interviewVOListToInterviewExcelTemplateList(List interviewVOList);
+ List interviewVOListToInterviewExcelTemplateList(List interviewVOList);
}
diff --git a/src/main/java/com/achobeta/domain/interview/model/dao/mapper/InterviewMapper.java b/src/main/java/com/achobeta/domain/interview/model/dao/mapper/InterviewMapper.java
index caa12348..0fe15a8e 100644
--- a/src/main/java/com/achobeta/domain/interview/model/dao/mapper/InterviewMapper.java
+++ b/src/main/java/com/achobeta/domain/interview/model/dao/mapper/InterviewMapper.java
@@ -17,7 +17,7 @@
*/
public interface InterviewMapper extends BaseMapper {
- List managerGetInterviewList(@Param("managerId") Long managerId, @Param("condition") InterviewConditionDTO interviewConditionDTO);
+ List managerGetInterviewList(@Param("managerId") Long managerId, @Param("condition") InterviewConditionDTO interviewConditionDTO);
List userGetInterviewList(@Param("userId") Long userId, @Param("condition") InterviewConditionDTO interviewConditionDTO);
diff --git a/src/main/java/com/achobeta/domain/interview/model/vo/InterviewExcelTemplate.java b/src/main/java/com/achobeta/domain/interview/model/vo/InterviewExcelTemplate.java
index f098ac90..18443734 100644
--- a/src/main/java/com/achobeta/domain/interview/model/vo/InterviewExcelTemplate.java
+++ b/src/main/java/com/achobeta/domain/interview/model/vo/InterviewExcelTemplate.java
@@ -22,6 +22,12 @@ public class InterviewExcelTemplate {
@Excel(name = "状态", width = 20)
private InterviewStatus status;
+ @Excel(name = "说明", width = 50)
+ private String description;
+
+ @Excel(name = "地址", width = 50)
+ private String address;
+
@ExcelEntity(name = "面试预约")
private ScheduleVO scheduleVO;
diff --git a/src/main/java/com/achobeta/domain/interview/service/InterviewService.java b/src/main/java/com/achobeta/domain/interview/service/InterviewService.java
index 1837643c..17374b1e 100644
--- a/src/main/java/com/achobeta/domain/interview/service/InterviewService.java
+++ b/src/main/java/com/achobeta/domain/interview/service/InterviewService.java
@@ -29,7 +29,7 @@ public interface InterviewService extends IService {
List getInterviewListByScheduleId(Long scheduleId);
- List managerGetInterviewList(Long managerId, InterviewConditionDTO condition);
+ List managerGetInterviewList(Long managerId, InterviewConditionDTO condition);
OnlineResourceVO printAllInterviewList(Long managerId, InterviewConditionDTO condition, ResourceAccessLevel level, Boolean synchronous);
@@ -49,7 +49,7 @@ public interface InterviewService extends IService {
InterviewStatus executeInterviewStateEvent(InterviewEvent interviewEvent, InterviewContext interviewContext);
- void setPaperForInterview(Long interviewId, Long paperId);
+ void setPaperForInterview(Interview interview, Long paperId);
// 检测 ------------------------------------------
@@ -57,6 +57,4 @@ public interface InterviewService extends IService {
Interview checkAndGetInterviewExists(Long interviewId);
- void checkInterviewStatus(Long interviewId, List interviewStatus);
-
}
diff --git a/src/main/java/com/achobeta/domain/interview/service/impl/InterviewServiceImpl.java b/src/main/java/com/achobeta/domain/interview/service/impl/InterviewServiceImpl.java
index 716cc919..38104fce 100644
--- a/src/main/java/com/achobeta/domain/interview/service/impl/InterviewServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/interview/service/impl/InterviewServiceImpl.java
@@ -74,13 +74,13 @@ public List getInterviewListByScheduleId(Long scheduleId) {
}
@Override
- public List managerGetInterviewList(Long managerId, InterviewConditionDTO condition) {
+ public List managerGetInterviewList(Long managerId, InterviewConditionDTO condition) {
return interviewMapper.managerGetInterviewList(managerId, condition);
}
@Override
public OnlineResourceVO printAllInterviewList(Long managerId, InterviewConditionDTO condition, ResourceAccessLevel level, Boolean synchronous) {
- List interviewVOList = managerGetInterviewList(null, condition);
+ List interviewVOList = managerGetInterviewList(null, condition);
// 上传表格到对象存储服务器
ExcelTemplateEnum achobetaInterviewAll = ExcelTemplateEnum.ACHOBETA_INTERVIEW_ALL;
return resourceService.uploadExcel(
@@ -161,13 +161,14 @@ public InterviewStatus executeInterviewStateEvent(InterviewEvent interviewEvent,
@Override
@Transactional
- public void setPaperForInterview(Long interviewId, Long paperId) {
+ public void setPaperForInterview(Interview interview, Long paperId) {
// 删除面试相关的打分
+ Long interviewId = interview.getId();
Db.lambdaUpdate(InterviewQuestionScore.class)
.eq(InterviewQuestionScore::getInterviewId, interviewId)
.remove();
// 拷贝一份试卷
- Long newPaperId = paperQuestionLinkService.cloneQuestionPaper(paperId);
+ Long newPaperId = paperQuestionLinkService.cloneQuestionPaper(paperId, interview.getTitle());
// 设置试卷
this.lambdaUpdate()
.eq(Interview::getId, interviewId)
@@ -187,10 +188,4 @@ public Interview checkAndGetInterviewExists(Long interviewId) {
new GlobalServiceException(GlobalServiceStatusCode.INTERVIEW_NOT_EXISTS));
}
- @Override
- public void checkInterviewStatus(Long interviewId, List interviewStatus) {
- checkAndGetInterviewExists(interviewId)
- .getStatus()
- .check(interviewStatus);
- }
}
diff --git a/src/main/java/com/achobeta/domain/login/model/dto/SmsLoginDTO.java b/src/main/java/com/achobeta/domain/login/model/dto/SmsLoginDTO.java
index 99dc0eb2..492e7f93 100644
--- a/src/main/java/com/achobeta/domain/login/model/dto/SmsLoginDTO.java
+++ b/src/main/java/com/achobeta/domain/login/model/dto/SmsLoginDTO.java
@@ -1,7 +1,7 @@
package com.achobeta.domain.login.model.dto;
+import com.achobeta.common.annotation.MobilePhone;
import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.Pattern;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@@ -25,7 +25,7 @@ public class SmsLoginDTO implements Serializable {
* 手机号
*/
@NotBlank(message = "手机号不能为空")
- @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号非法")
+ @MobilePhone
private String phoneNumber;
/**
diff --git a/src/main/java/com/achobeta/domain/message/handler/chain/MessageSendDelayChain.java b/src/main/java/com/achobeta/domain/message/handler/chain/MessageSendDelayChain.java
index 5912c613..cc8429db 100644
--- a/src/main/java/com/achobeta/domain/message/handler/chain/MessageSendDelayChain.java
+++ b/src/main/java/com/achobeta/domain/message/handler/chain/MessageSendDelayChain.java
@@ -9,6 +9,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
import java.time.Duration;
import java.time.LocalDateTime;
@@ -37,6 +38,7 @@ private MessageSendHandler initHandlerChain() {
}
@Override
+ @Transactional
public void handleChain(MessageSendDTO messageSendBody, CopyOnWriteArraySet webSocketSet) {
//初始化责任链
MessageSendHandler messageSendHandler = initHandlerChain();
diff --git a/src/main/java/com/achobeta/domain/message/handler/chain/MessageSendNowChain.java b/src/main/java/com/achobeta/domain/message/handler/chain/MessageSendNowChain.java
index 72ca72ed..74e8e3b1 100644
--- a/src/main/java/com/achobeta/domain/message/handler/chain/MessageSendNowChain.java
+++ b/src/main/java/com/achobeta/domain/message/handler/chain/MessageSendNowChain.java
@@ -6,6 +6,7 @@
import com.achobeta.domain.message.model.dto.MessageSendDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArraySet;
@@ -27,6 +28,7 @@ private MessageSendHandler initHandlerChain() {
}
@Override
+ @Transactional
public void handleChain(MessageSendDTO messageSendBody, CopyOnWriteArraySet webSocketSet) {
//初始化责任链
MessageSendHandler messageSendHandler = initHandlerChain();
diff --git a/src/main/java/com/achobeta/domain/message/service/impl/MessageServiceImpl.java b/src/main/java/com/achobeta/domain/message/service/impl/MessageServiceImpl.java
index f665fa43..3a289c2b 100644
--- a/src/main/java/com/achobeta/domain/message/service/impl/MessageServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/message/service/impl/MessageServiceImpl.java
@@ -64,7 +64,7 @@ public QueryStuListVO queryStuListByCondition(QueryStuListDTO queryStuDTO) {
@Override
public List queryStuList(Long batchId, List userIds) {
- List stuResumeList = stuResumeService.queryStuList(batchId, userIds.stream().distinct().toList());
+ List stuResumeList = stuResumeService.queryStuList(batchId, userIds);
return messageConverter.stuResumeListToStuBaseInfoDTOList(stuResumeList);
}
diff --git a/src/main/java/com/achobeta/domain/paper/constants/PaperLibraryConstants.java b/src/main/java/com/achobeta/domain/paper/constants/PaperLibraryConstants.java
new file mode 100644
index 00000000..17446db6
--- /dev/null
+++ b/src/main/java/com/achobeta/domain/paper/constants/PaperLibraryConstants.java
@@ -0,0 +1,14 @@
+package com.achobeta.domain.paper.constants;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-16
+ * Time: 21:24
+ */
+public interface PaperLibraryConstants {
+
+ String PAPER_LIBRARY_REFERENCE_PAPERS_LOCK = "paperLibraryReferencePapersLock:";
+
+}
diff --git a/src/main/java/com/achobeta/domain/paper/constants/QuestionPaperConstants.java b/src/main/java/com/achobeta/domain/paper/constants/QuestionPaperConstants.java
new file mode 100644
index 00000000..23176cbd
--- /dev/null
+++ b/src/main/java/com/achobeta/domain/paper/constants/QuestionPaperConstants.java
@@ -0,0 +1,14 @@
+package com.achobeta.domain.paper.constants;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-16
+ * Time: 21:36
+ */
+public interface QuestionPaperConstants {
+
+ String PAPER_ADD_QUESTIONS_LOCK = "paperAddQuestionsLock:";
+
+}
diff --git a/src/main/java/com/achobeta/domain/paper/controller/PaperLibraryController.java b/src/main/java/com/achobeta/domain/paper/controller/PaperLibraryController.java
index 6442b9e8..682bb666 100644
--- a/src/main/java/com/achobeta/domain/paper/controller/PaperLibraryController.java
+++ b/src/main/java/com/achobeta/domain/paper/controller/PaperLibraryController.java
@@ -4,9 +4,11 @@
import com.achobeta.common.annotation.Intercept;
import com.achobeta.common.enums.UserTypeEnum;
import com.achobeta.domain.paper.model.converter.LibraryConverter;
+import com.achobeta.domain.paper.model.dto.LibraryReferencePaperDTO;
import com.achobeta.domain.paper.model.dto.PaperLibraryDTO;
import com.achobeta.domain.paper.model.entity.QuestionPaperLibrary;
import com.achobeta.domain.paper.service.QuestionPaperLibraryService;
+import com.achobeta.domain.paper.service.QuestionPaperService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
@@ -33,12 +35,23 @@ public class PaperLibraryController {
private final QuestionPaperLibraryService questionPaperLibraryService;
+ private final QuestionPaperService questionPaperService;
+
@PostMapping("/create")
public SystemJsonResponse createPaperLibrary(@RequestParam("libType") @NotBlank String libType) {
Long paperLibraryId = questionPaperLibraryService.createPaperLibrary(libType);
return SystemJsonResponse.SYSTEM_SUCCESS(paperLibraryId);
}
+ @PostMapping("/reference")
+ public SystemJsonResponse referencePapers(@Valid @RequestBody LibraryReferencePaperDTO libraryReferencePaperDTO) {
+ Long libId = libraryReferencePaperDTO.getLibId();
+ questionPaperLibraryService.checkPaperLibraryExists(libId);
+ // 引用
+ questionPaperService.referencePapers(libraryReferencePaperDTO.getLibId(), libraryReferencePaperDTO.getPaperIds());
+ return SystemJsonResponse.SYSTEM_SUCCESS();
+ }
+
@PostMapping("/rename")
public SystemJsonResponse renamePaperLibrary(@Valid @RequestBody PaperLibraryDTO paperLibraryDTO) {
// 检查
diff --git a/src/main/java/com/achobeta/domain/paper/handler/chain/RemovePaperHandlerChain.java b/src/main/java/com/achobeta/domain/paper/handler/chain/RemovePaperHandlerChain.java
index c03799d8..c2bc5438 100644
--- a/src/main/java/com/achobeta/domain/paper/handler/chain/RemovePaperHandlerChain.java
+++ b/src/main/java/com/achobeta/domain/paper/handler/chain/RemovePaperHandlerChain.java
@@ -5,6 +5,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@@ -39,6 +40,7 @@ public void doPostConstruct() {
}
@Override
+ @Transactional
public void handle(Long paperId) {
log.info("责任链开始处理 [paperId 为 {}] 的“删除试卷”事件", paperId);
super.doNextHandler(paperId);
diff --git a/src/main/java/com/achobeta/domain/paper/handler/chain/RemoveQuestionFromPaperHandlerChain.java b/src/main/java/com/achobeta/domain/paper/handler/chain/RemoveQuestionFromPaperHandlerChain.java
index 3fe882ee..cca60772 100644
--- a/src/main/java/com/achobeta/domain/paper/handler/chain/RemoveQuestionFromPaperHandlerChain.java
+++ b/src/main/java/com/achobeta/domain/paper/handler/chain/RemoveQuestionFromPaperHandlerChain.java
@@ -5,6 +5,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@@ -39,6 +40,7 @@ public void doPostConstruct() {
}
@Override
+ @Transactional
public void handle(Long paperId, List questionIds) {
log.info("责任链开始处理 [paperId 为 {},questionIds 为 {}] 的“从试卷中移除若干题”事件", paperId, questionIds);
super.doNextHandler(paperId, questionIds);
diff --git a/src/main/java/com/achobeta/domain/paper/handler/ext/RemovePaperLPLinkHandler.java b/src/main/java/com/achobeta/domain/paper/handler/ext/RemovePaperLPLinkHandler.java
index 642e2b55..65a4c1ef 100644
--- a/src/main/java/com/achobeta/domain/paper/handler/ext/RemovePaperLPLinkHandler.java
+++ b/src/main/java/com/achobeta/domain/paper/handler/ext/RemovePaperLPLinkHandler.java
@@ -2,7 +2,9 @@
import com.achobeta.domain.paper.handler.RemovePaperHandler;
import com.achobeta.domain.paper.model.entity.LibraryPaperLink;
+import com.achobeta.domain.paper.model.entity.PaperQuestionLink;
import com.achobeta.domain.paper.service.LibraryPaperLinkService;
+import com.achobeta.domain.paper.service.PaperQuestionLinkService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@@ -19,12 +21,17 @@ public class RemovePaperLPLinkHandler extends RemovePaperHandler {
private final LibraryPaperLinkService libraryPaperLinkService;
+ private final PaperQuestionLinkService paperQuestionLinkService;
+
@Override
public void handle(Long paperId) {
// 删除关联表的一些行
libraryPaperLinkService.lambdaUpdate()
.eq(LibraryPaperLink::getPaperId, paperId)
.remove();
+ paperQuestionLinkService.lambdaUpdate()
+ .eq(PaperQuestionLink::getPaperId, paperId)
+ .remove();
super.doNextHandler(paperId);
}
diff --git a/src/main/java/com/achobeta/domain/paper/model/dao/mapper/QuestionPaperMapper.java b/src/main/java/com/achobeta/domain/paper/model/dao/mapper/QuestionPaperMapper.java
index d8270db0..2b0993f1 100644
--- a/src/main/java/com/achobeta/domain/paper/model/dao/mapper/QuestionPaperMapper.java
+++ b/src/main/java/com/achobeta/domain/paper/model/dao/mapper/QuestionPaperMapper.java
@@ -17,6 +17,8 @@ public interface QuestionPaperMapper extends BaseMapper {
// 并不会将结果集加入 page,而是返回值 IPage 里
IPage queryPapers(IPage page, @Param("libIds") List libIds);
+
+ List getPapers(@Param("libIds") List libIds);
}
diff --git a/src/main/java/com/achobeta/domain/paper/model/dto/LibraryReferencePaperDTO.java b/src/main/java/com/achobeta/domain/paper/model/dto/LibraryReferencePaperDTO.java
new file mode 100644
index 00000000..fc3fc0f9
--- /dev/null
+++ b/src/main/java/com/achobeta/domain/paper/model/dto/LibraryReferencePaperDTO.java
@@ -0,0 +1,25 @@
+package com.achobeta.domain.paper.model.dto;
+
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-16
+ * Time: 20:43
+ */
+@Data
+public class LibraryReferencePaperDTO {
+
+ @NotNull(message = "试卷库 id 不能为空")
+ private Long libId;
+
+ @NotEmpty(message = "试卷 id 列表不能为空")
+ private List paperIds;
+
+}
diff --git a/src/main/java/com/achobeta/domain/paper/model/dto/PaperLibraryDTO.java b/src/main/java/com/achobeta/domain/paper/model/dto/PaperLibraryDTO.java
index e6de6bc9..7d9dfbde 100644
--- a/src/main/java/com/achobeta/domain/paper/model/dto/PaperLibraryDTO.java
+++ b/src/main/java/com/achobeta/domain/paper/model/dto/PaperLibraryDTO.java
@@ -14,7 +14,7 @@
@Data
public class PaperLibraryDTO {
- @NotNull(message = "库的 id 不能为空")
+ @NotNull(message = "试卷库 id 不能为空")
private Long libId;
@NotBlank(message = "库的类型不能为空")
diff --git a/src/main/java/com/achobeta/domain/paper/model/dto/PaperQuestionLinkDTO.java b/src/main/java/com/achobeta/domain/paper/model/dto/PaperQuestionLinkDTO.java
index 34f39141..8a149324 100644
--- a/src/main/java/com/achobeta/domain/paper/model/dto/PaperQuestionLinkDTO.java
+++ b/src/main/java/com/achobeta/domain/paper/model/dto/PaperQuestionLinkDTO.java
@@ -1,5 +1,6 @@
package com.achobeta.domain.paper.model.dto;
+import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@@ -18,7 +19,7 @@ public class PaperQuestionLinkDTO {
@NotNull(message = "试卷 id 不能为空")
private Long paperId;
- @NotNull(message = "问题 ids 不能为空")
+ @NotEmpty(message = "问题 ids 不能为空")
private List questionIds;
}
diff --git a/src/main/java/com/achobeta/domain/paper/model/dto/QuestionPaperDTO.java b/src/main/java/com/achobeta/domain/paper/model/dto/QuestionPaperDTO.java
index e15294e2..24361403 100644
--- a/src/main/java/com/achobeta/domain/paper/model/dto/QuestionPaperDTO.java
+++ b/src/main/java/com/achobeta/domain/paper/model/dto/QuestionPaperDTO.java
@@ -1,7 +1,7 @@
package com.achobeta.domain.paper.model.dto;
import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.util.List;
@@ -16,7 +16,7 @@
@Data
public class QuestionPaperDTO {
- @NotNull(message = "试卷库 ids 不能为空")
+ @NotEmpty(message = "试卷库 ids 不能为空")
private List libIds;
@NotBlank(message = "题目不能为空")
@@ -25,5 +25,4 @@ public class QuestionPaperDTO {
@NotBlank(message = "试卷说明不能为空")
private String description;
-
}
diff --git a/src/main/java/com/achobeta/domain/paper/service/PaperQuestionLinkService.java b/src/main/java/com/achobeta/domain/paper/service/PaperQuestionLinkService.java
index 0cd292ad..79edab6a 100644
--- a/src/main/java/com/achobeta/domain/paper/service/PaperQuestionLinkService.java
+++ b/src/main/java/com/achobeta/domain/paper/service/PaperQuestionLinkService.java
@@ -25,7 +25,7 @@ public interface PaperQuestionLinkService extends IService {
QuestionPaperDetailVO getPaperDetail(Long paperId);
- Long cloneQuestionPaper(Long paperId);
+ Long cloneQuestionPaper(Long paperId, String title);
void checkQuestionExistInPaper(Long paperId, Long questionId);
diff --git a/src/main/java/com/achobeta/domain/paper/service/QuestionPaperService.java b/src/main/java/com/achobeta/domain/paper/service/QuestionPaperService.java
index 5565f0c9..2363f269 100644
--- a/src/main/java/com/achobeta/domain/paper/service/QuestionPaperService.java
+++ b/src/main/java/com/achobeta/domain/paper/service/QuestionPaperService.java
@@ -21,6 +21,8 @@ public interface QuestionPaperService extends IService {
Long addQuestionPaper(List libIds, String title, String description);
+ void referencePapers(Long libId, List paperIds);
+
void updateQuestionPaper(Long paperId, List libIds, String title, String description);
/**
diff --git a/src/main/java/com/achobeta/domain/paper/service/impl/PaperQuestionLinkServiceImpl.java b/src/main/java/com/achobeta/domain/paper/service/impl/PaperQuestionLinkServiceImpl.java
index 0b15347c..85cc55e3 100644
--- a/src/main/java/com/achobeta/domain/paper/service/impl/PaperQuestionLinkServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/paper/service/impl/PaperQuestionLinkServiceImpl.java
@@ -1,6 +1,7 @@
package com.achobeta.domain.paper.service.impl;
import com.achobeta.common.enums.GlobalServiceStatusCode;
+import com.achobeta.domain.paper.constants.QuestionPaperConstants;
import com.achobeta.domain.paper.model.dao.mapper.PaperQuestionLinkMapper;
import com.achobeta.domain.paper.model.dao.mapper.QuestionPaperLibraryMapper;
import com.achobeta.domain.paper.model.entity.PaperQuestionLink;
@@ -10,15 +11,21 @@
import com.achobeta.domain.paper.service.QuestionPaperService;
import com.achobeta.domain.question.model.vo.QuestionVO;
import com.achobeta.exception.GlobalServiceException;
+import com.achobeta.redis.lock.RedisLock;
+import com.achobeta.redis.lock.strategy.SimpleLockStrategy;
+import com.achobeta.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
-import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* @author 马拉圈
@@ -36,6 +43,10 @@ public class PaperQuestionLinkServiceImpl extends ServiceImpl getQuestionsOnPaper(Long paperId) {
return paperQuestionLinkMapper.getQuestionsOnPaper(paperId);
@@ -52,27 +63,32 @@ public Optional getPaperQuestionLink(Long paperId, Long quest
@Override
@Transactional
public void addQuestionsForPaper(Long paperId, List questionIds) {
- Set hash = new HashSet<>();
- // 获取试卷的所有题
- getQuestionsOnPaper(paperId).forEach(questionVO -> hash.add(questionVO.getId()));
- // 将不存在于原试卷的题滤出来
- List paperQuestionLinks = questionIds.stream()
- .filter(questionId -> !hash.contains(questionId))
- .map(questionId -> {
- PaperQuestionLink paperQuestionLink = new PaperQuestionLink();
- paperQuestionLink.setPaperId(paperId);
- paperQuestionLink.setQuestionId(questionId);
- return paperQuestionLink;
- }).toList();
- this.saveBatch(paperQuestionLinks);
+ redisLock.tryLockDoSomething(QuestionPaperConstants.PAPER_ADD_QUESTIONS_LOCK + paperId, () -> {
+ // 获取试卷的所有题
+ Set hash = getQuestionsOnPaper(paperId).stream().map(QuestionVO::getId).collect(Collectors.toSet());
+ // 将不存在于原试卷的题滤出来
+ List paperQuestionLinks = questionIds.stream()
+ .distinct()
+ .filter(questionId -> Objects.nonNull(questionId) && !hash.contains(questionId))
+ .map(questionId -> {
+ PaperQuestionLink paperQuestionLink = new PaperQuestionLink();
+ paperQuestionLink.setPaperId(paperId);
+ paperQuestionLink.setQuestionId(questionId);
+ return paperQuestionLink;
+ }).toList();
+ this.saveBatch(paperQuestionLinks);
+ }, () -> {}, simpleLockStrategy);
}
@Override
public void removeQuestionsFromPaper(Long paperId, List questionIds) {
- this.lambdaUpdate()
- .eq(PaperQuestionLink::getPaperId, paperId)
- .in(PaperQuestionLink::getQuestionId, questionIds)
- .remove();
+ questionIds = ObjectUtil.distinctNonNullStream(questionIds).toList();
+ if(!CollectionUtils.isEmpty(questionIds)) {
+ this.lambdaUpdate()
+ .eq(PaperQuestionLink::getPaperId, paperId)
+ .in(PaperQuestionLink::getQuestionId, questionIds)
+ .remove();
+ }
}
@Override
@@ -85,15 +101,18 @@ public QuestionPaperDetailVO getPaperDetail(Long paperId) {
@Override
@Transactional
- public Long cloneQuestionPaper(Long paperId) {
+ public Long cloneQuestionPaper(Long paperId, String title) {
// 拷贝试卷的定义
QuestionPaperDetailVO paperDetail = getPaperDetail(paperId);
List libIds = paperDetail.getTypes()
.stream()
.map(PaperLibraryVO::getId)
.toList();
- Long newPaperId = questionPaperService.addQuestionPaper(libIds,
- paperDetail.getTitle(), paperDetail.getDescription());
+ Long newPaperId = questionPaperService.addQuestionPaper(
+ libIds,
+ Optional.ofNullable(title).filter(StringUtils::hasText).orElseGet(paperDetail::getTitle),
+ paperDetail.getDescription()
+ );
// 拷贝试卷的题目
List questionIds = paperDetail.getQuestions()
.stream()
diff --git a/src/main/java/com/achobeta/domain/paper/service/impl/QuestionPaperServiceImpl.java b/src/main/java/com/achobeta/domain/paper/service/impl/QuestionPaperServiceImpl.java
index eff1936b..213c9178 100644
--- a/src/main/java/com/achobeta/domain/paper/service/impl/QuestionPaperServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/paper/service/impl/QuestionPaperServiceImpl.java
@@ -3,6 +3,7 @@
import com.achobeta.common.base.BasePageQuery;
import com.achobeta.common.base.BasePageResult;
import com.achobeta.common.enums.GlobalServiceStatusCode;
+import com.achobeta.domain.paper.constants.PaperLibraryConstants;
import com.achobeta.domain.paper.model.converter.QuestionPaperConverter;
import com.achobeta.domain.paper.model.dao.mapper.QuestionPaperMapper;
import com.achobeta.domain.paper.model.dto.PaperQueryDTO;
@@ -12,6 +13,8 @@
import com.achobeta.domain.paper.service.LibraryPaperLinkService;
import com.achobeta.domain.paper.service.QuestionPaperService;
import com.achobeta.exception.GlobalServiceException;
+import com.achobeta.redis.lock.RedisLock;
+import com.achobeta.redis.lock.strategy.SimpleLockStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
@@ -19,6 +22,7 @@
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
+import java.util.stream.Collectors;
/**
* @author 马拉圈
@@ -34,6 +38,10 @@ public class QuestionPaperServiceImpl extends ServiceImpl BasePageQuery -> page -> BasePageResult -> vo
* @param paperQueryDTO 分页参数
@@ -77,6 +85,23 @@ public Long addQuestionPaper(List libIds, String title, String description
return paperId;
}
+ @Override
+ public void referencePapers(Long libId, List paperIds) {
+ redisLock.tryLockDoSomething(PaperLibraryConstants.PAPER_LIBRARY_REFERENCE_PAPERS_LOCK + libId, () -> {
+ Set hash = questionPaperMapper.getPapers(List.of(libId)).stream().map(QuestionPaper::getId).collect(Collectors.toSet());
+ List libraryPaperLinkList = paperIds.stream()
+ .distinct()
+ .filter(paperId -> Objects.nonNull(paperId) && !hash.contains(paperId))
+ .map(paperId -> {
+ LibraryPaperLink libraryPaperLink = new LibraryPaperLink();
+ libraryPaperLink.setPaperId(paperId);
+ libraryPaperLink.setLibId(libId);
+ return libraryPaperLink;
+ }).toList();
+ libraryPaperLinkService.saveBatch(libraryPaperLinkList);
+ }, () -> {}, simpleLockStrategy);
+ }
+
@Override
@Transactional
public void updateQuestionPaper(Long paperId, List libIds, String title, String description) {
diff --git a/src/main/java/com/achobeta/domain/question/constants/QuestionLibraryConstants.java b/src/main/java/com/achobeta/domain/question/constants/QuestionLibraryConstants.java
new file mode 100644
index 00000000..ebdb40fa
--- /dev/null
+++ b/src/main/java/com/achobeta/domain/question/constants/QuestionLibraryConstants.java
@@ -0,0 +1,14 @@
+package com.achobeta.domain.question.constants;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-16
+ * Time: 21:30
+ */
+public interface QuestionLibraryConstants {
+
+ String QUESTION_LIBRARY_REFERENCE_QUESTIONS_LOCK = "questionLibraryReferenceQuestionsLock:";
+
+}
diff --git a/src/main/java/com/achobeta/domain/question/controller/QuestionLibraryController.java b/src/main/java/com/achobeta/domain/question/controller/QuestionLibraryController.java
index 75929d49..ee253f51 100644
--- a/src/main/java/com/achobeta/domain/question/controller/QuestionLibraryController.java
+++ b/src/main/java/com/achobeta/domain/question/controller/QuestionLibraryController.java
@@ -4,9 +4,11 @@
import com.achobeta.common.annotation.Intercept;
import com.achobeta.common.enums.UserTypeEnum;
import com.achobeta.domain.paper.model.converter.LibraryConverter;
+import com.achobeta.domain.question.model.dto.LibraryReferenceQuestionDTO;
import com.achobeta.domain.question.model.dto.QuestionLibraryDTO;
import com.achobeta.domain.question.model.entity.QuestionLibrary;
import com.achobeta.domain.question.service.QuestionLibraryService;
+import com.achobeta.domain.question.service.QuestionService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
@@ -33,12 +35,23 @@ public class QuestionLibraryController {
private final QuestionLibraryService questionLibraryService;
+ private final QuestionService questionService;
+
@PostMapping("/create")
public SystemJsonResponse createQuestionLibrary(@RequestParam("libType") @NotBlank String libType) {
Long questionLibraryId = questionLibraryService.createQuestionLibrary(libType);
return SystemJsonResponse.SYSTEM_SUCCESS(questionLibraryId);
}
+ @PostMapping("/reference")
+ public SystemJsonResponse referenceQuestions(@Valid @RequestBody LibraryReferenceQuestionDTO libraryReferenceQuestionDTO) {
+ Long libId = libraryReferenceQuestionDTO.getLibId();
+ questionLibraryService.checkQuestionLibraryExists(libId);
+ // 引用
+ questionService.referenceQuestions(libraryReferenceQuestionDTO.getLibId(), libraryReferenceQuestionDTO.getQuestionIds());
+ return SystemJsonResponse.SYSTEM_SUCCESS();
+ }
+
@PostMapping("/rename")
public SystemJsonResponse renameQuestionLibrary(@Valid @RequestBody QuestionLibraryDTO questionLibraryDTO) {
// 检查
diff --git a/src/main/java/com/achobeta/domain/question/handler/chain/RemoveQuestionHandlerChain.java b/src/main/java/com/achobeta/domain/question/handler/chain/RemoveQuestionHandlerChain.java
index 7a93dad3..c7d5ad61 100644
--- a/src/main/java/com/achobeta/domain/question/handler/chain/RemoveQuestionHandlerChain.java
+++ b/src/main/java/com/achobeta/domain/question/handler/chain/RemoveQuestionHandlerChain.java
@@ -5,6 +5,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@@ -39,6 +40,7 @@ public void doPostConstruct() {
}
@Override
+ @Transactional
public void handle(Long questionId) {
log.info("责任链开始处理 [questionId 为 {}] 的“删除问题”事件", questionId);
super.doNextHandler(questionId);
diff --git a/src/main/java/com/achobeta/domain/question/model/dao/mapper/QuestionMapper.java b/src/main/java/com/achobeta/domain/question/model/dao/mapper/QuestionMapper.java
index abcb0c6a..eb41d0d2 100644
--- a/src/main/java/com/achobeta/domain/question/model/dao/mapper/QuestionMapper.java
+++ b/src/main/java/com/achobeta/domain/question/model/dao/mapper/QuestionMapper.java
@@ -18,6 +18,8 @@ public interface QuestionMapper extends BaseMapper {
// 并不会将结果集加入 page,而是返回值 IPage 里
IPage queryQuestions(IPage page, @Param("libIds") List libIds);
+ List getQuestions(@Param("libIds") List libIds);
+
}
diff --git a/src/main/java/com/achobeta/domain/question/model/dto/LibraryReferenceQuestionDTO.java b/src/main/java/com/achobeta/domain/question/model/dto/LibraryReferenceQuestionDTO.java
new file mode 100644
index 00000000..9de7a50b
--- /dev/null
+++ b/src/main/java/com/achobeta/domain/question/model/dto/LibraryReferenceQuestionDTO.java
@@ -0,0 +1,25 @@
+package com.achobeta.domain.question.model.dto;
+
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-16
+ * Time: 20:22
+ */
+@Data
+public class LibraryReferenceQuestionDTO {
+
+ @NotNull(message = "题库 id 不能为空")
+ private Long libId;
+
+ @NotEmpty(message = "问题 id 列表不能为空")
+ private List questionIds;
+
+}
diff --git a/src/main/java/com/achobeta/domain/question/model/dto/QuestionLibraryDTO.java b/src/main/java/com/achobeta/domain/question/model/dto/QuestionLibraryDTO.java
index 3064be85..41cea0b5 100644
--- a/src/main/java/com/achobeta/domain/question/model/dto/QuestionLibraryDTO.java
+++ b/src/main/java/com/achobeta/domain/question/model/dto/QuestionLibraryDTO.java
@@ -14,7 +14,7 @@
@Data
public class QuestionLibraryDTO {
- @NotNull(message = "库的 id 不能为空")
+ @NotNull(message = "题库 id 不能为空")
private Long libId;
@NotBlank(message = "库的类型不能为空")
diff --git a/src/main/java/com/achobeta/domain/question/service/QuestionService.java b/src/main/java/com/achobeta/domain/question/service/QuestionService.java
index 2bf8bce9..da9c9079 100644
--- a/src/main/java/com/achobeta/domain/question/service/QuestionService.java
+++ b/src/main/java/com/achobeta/domain/question/service/QuestionService.java
@@ -23,6 +23,8 @@ public interface QuestionService extends IService {
Long addQuestion(List libIds, String title, String standard);
+ void referenceQuestions(Long libId, List questionIds);
+
void saveBatchQuestion(QuestionSaveBatchDTO questionSaveBatchDTO);
void updateQuestion(Long questionId, List libIds, String title, String standard);
diff --git a/src/main/java/com/achobeta/domain/question/service/impl/QuestionServiceImpl.java b/src/main/java/com/achobeta/domain/question/service/impl/QuestionServiceImpl.java
index 6c4c475e..c4dd241b 100644
--- a/src/main/java/com/achobeta/domain/question/service/impl/QuestionServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/question/service/impl/QuestionServiceImpl.java
@@ -3,6 +3,7 @@
import com.achobeta.common.base.BasePageQuery;
import com.achobeta.common.base.BasePageResult;
import com.achobeta.common.enums.GlobalServiceStatusCode;
+import com.achobeta.domain.question.constants.QuestionLibraryConstants;
import com.achobeta.domain.question.model.converter.QuestionConverter;
import com.achobeta.domain.question.model.dao.mapper.QuestionLibraryMapper;
import com.achobeta.domain.question.model.dao.mapper.QuestionMapper;
@@ -19,6 +20,8 @@
import com.achobeta.domain.question.service.QuestionLibraryService;
import com.achobeta.domain.question.service.QuestionService;
import com.achobeta.exception.GlobalServiceException;
+import com.achobeta.redis.lock.RedisLock;
+import com.achobeta.redis.lock.strategy.SimpleLockStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
@@ -27,6 +30,7 @@
import org.springframework.util.CollectionUtils;
import java.util.*;
+import java.util.stream.Collectors;
/**
* @author 马拉圈
@@ -38,7 +42,6 @@
public class QuestionServiceImpl extends ServiceImpl
implements QuestionService{
-
private final QuestionMapper questionMapper;
private final QuestionLibraryMapper questionLibraryMapper;
@@ -47,6 +50,10 @@ public class QuestionServiceImpl extends ServiceImpl
private final LibraryQuestionLinkService libraryQuestionLinkService;
+ private final RedisLock redisLock;
+
+ private final SimpleLockStrategy simpleLockStrategy;
+
/**
* 流程:dto -> BasePageQuery -> page -> BasePageResult -> vo
* @param questionQueryDTO 分页参数
@@ -90,6 +97,23 @@ public Long addQuestion(List libIds, String title, String standard) {
return questionId;
}
+ @Override
+ public void referenceQuestions(Long libId, List questionIds) {
+ redisLock.tryLockDoSomething(QuestionLibraryConstants.QUESTION_LIBRARY_REFERENCE_QUESTIONS_LOCK + libId, () -> {
+ Set hash = questionMapper.getQuestions(List.of(libId)).stream().map(Question::getId).collect(Collectors.toSet());
+ List libraryQuestionLinkList = questionIds.stream()
+ .distinct()
+ .filter(questionId -> Objects.nonNull(questionId) && !hash.contains(questionId))
+ .map(questionId -> {
+ LibraryQuestionLink libraryQuestionLink = new LibraryQuestionLink();
+ libraryQuestionLink.setQuestionId(questionId);
+ libraryQuestionLink.setLibId(libId);
+ return libraryQuestionLink;
+ }).toList();
+ libraryQuestionLinkService.saveBatch(libraryQuestionLinkList);
+ }, () -> {}, simpleLockStrategy);
+ }
+
@Override
@Transactional
public void saveBatchQuestion(QuestionSaveBatchDTO questionSaveBatchDTO) {
diff --git a/src/main/java/com/achobeta/domain/recruit/handler/ext/RemovePaperPQLinkHandler.java b/src/main/java/com/achobeta/domain/recruit/handler/ext/RemovePaperPQLinkHandler.java
index 8c471131..880ae55d 100644
--- a/src/main/java/com/achobeta/domain/recruit/handler/ext/RemovePaperPQLinkHandler.java
+++ b/src/main/java/com/achobeta/domain/recruit/handler/ext/RemovePaperPQLinkHandler.java
@@ -32,22 +32,20 @@ public class RemovePaperPQLinkHandler extends RemovePaperHandler {
@Override
public void handle(Long paperId) {
List participationIds = activityParticipationService.getParticipationIdsByPaperId(paperId);
- if(CollectionUtils.isEmpty(participationIds)) {
- return;
+ if(!CollectionUtils.isEmpty(participationIds)) {
+ // 删除对应的行
+ participationQuestionLinkService.lambdaUpdate()
+ .in(ParticipationQuestionLink::getParticipationId, participationIds)
+ .remove();
}
- // 删除对应的行
- participationQuestionLinkService.lambdaUpdate()
- .in(ParticipationQuestionLink::getParticipationId, participationIds)
- .remove();
// 涉及的招新活动的 paperId 置为 null
List actIds = recruitmentActivityService.getActIdsByPaperId(paperId);
- if(CollectionUtils.isEmpty(actIds)) {
- return;
+ if(!CollectionUtils.isEmpty(actIds)) {
+ recruitmentActivityService.lambdaUpdate()
+ .in(RecruitmentActivity::getId, actIds)
+ .set(RecruitmentActivity::getPaperId, null)
+ .update();
}
- recruitmentActivityService.lambdaUpdate()
- .in(RecruitmentActivity::getId, actIds)
- .set(RecruitmentActivity::getPaperId, null)
- .update();
// 执行下一个
super.doNextHandler(paperId);
}
diff --git a/src/main/java/com/achobeta/domain/recruit/handler/ext/RemoveQuestionFromPaperPQLinkHandler.java b/src/main/java/com/achobeta/domain/recruit/handler/ext/RemoveQuestionFromPaperPQLinkHandler.java
index 5e055b32..61a8eff7 100644
--- a/src/main/java/com/achobeta/domain/recruit/handler/ext/RemoveQuestionFromPaperPQLinkHandler.java
+++ b/src/main/java/com/achobeta/domain/recruit/handler/ext/RemoveQuestionFromPaperPQLinkHandler.java
@@ -28,14 +28,13 @@ public class RemoveQuestionFromPaperPQLinkHandler extends RemoveQuestionFromPape
@Override
public void handle(Long paperId, List questionIds) {
List participationIds = activityParticipationService.getParticipationIdsByPaperId(paperId);
- if(CollectionUtils.isEmpty(participationIds)) {
- return;
+ if(!CollectionUtils.isEmpty(participationIds) && !CollectionUtils.isEmpty(questionIds)) {
+ // 删除对应的行
+ participationQuestionLinkService.lambdaUpdate()
+ .in(ParticipationQuestionLink::getParticipationId, participationIds)
+ .in(ParticipationQuestionLink::getQuestionId, questionIds)
+ .remove();
}
- // 删除对应的行
- participationQuestionLinkService.lambdaUpdate()
- .in(ParticipationQuestionLink::getParticipationId, participationIds)
- .in(ParticipationQuestionLink::getQuestionId, questionIds)
- .remove();
// 执行下一个
super.doNextHandler(paperId, questionIds);
}
diff --git a/src/main/java/com/achobeta/domain/recruit/model/condition/allmatch/StatusCondition.java b/src/main/java/com/achobeta/domain/recruit/model/condition/allmatch/StatusCondition.java
index a509681e..d075ab78 100644
--- a/src/main/java/com/achobeta/domain/recruit/model/condition/allmatch/StatusCondition.java
+++ b/src/main/java/com/achobeta/domain/recruit/model/condition/allmatch/StatusCondition.java
@@ -2,9 +2,9 @@
import com.achobeta.domain.recruit.model.condition.function.StudentCondition;
import com.achobeta.domain.student.model.entity.StuResume;
+import com.achobeta.util.ObjectUtil;
import java.util.ArrayList;
-import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -18,11 +18,8 @@ public class StatusCondition extends ArrayList implements StudentCondit
@Override
public Predicate predicate() {
- return stuResume -> this
- .stream()
- .filter(Objects::nonNull)
- .anyMatch(status -> status.equals(stuResume.getStatus().getCode()))
- ;
+ return stuResume -> ObjectUtil.distinctNonNullStream(this)
+ .anyMatch(status -> status.equals(stuResume.getStatus().getCode()));
}
}
diff --git a/src/main/java/com/achobeta/domain/recruit/model/condition/anymatch/GradeCondition.java b/src/main/java/com/achobeta/domain/recruit/model/condition/anymatch/GradeCondition.java
index 40fde831..8bd56780 100644
--- a/src/main/java/com/achobeta/domain/recruit/model/condition/anymatch/GradeCondition.java
+++ b/src/main/java/com/achobeta/domain/recruit/model/condition/anymatch/GradeCondition.java
@@ -2,9 +2,9 @@
import com.achobeta.domain.recruit.model.condition.function.StudentCondition;
import com.achobeta.domain.student.model.entity.StuResume;
+import com.achobeta.util.ObjectUtil;
import java.util.ArrayList;
-import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -18,10 +18,7 @@ public class GradeCondition extends ArrayList implements StudentConditi
@Override
public Predicate predicate() {
- return stuResume -> this
- .stream()
- .filter(Objects::nonNull)
- .anyMatch(grade -> grade.equals(stuResume.getGrade()))
- ;
+ return stuResume -> ObjectUtil.distinctNonNullStream(this)
+ .anyMatch(grade -> grade.equals(stuResume.getGrade()));
}
}
diff --git a/src/main/java/com/achobeta/domain/recruit/model/condition/anymatch/UserIdCondition.java b/src/main/java/com/achobeta/domain/recruit/model/condition/anymatch/UserIdCondition.java
index 599efb2a..bdb2c5fe 100644
--- a/src/main/java/com/achobeta/domain/recruit/model/condition/anymatch/UserIdCondition.java
+++ b/src/main/java/com/achobeta/domain/recruit/model/condition/anymatch/UserIdCondition.java
@@ -2,9 +2,9 @@
import com.achobeta.domain.recruit.model.condition.function.StudentCondition;
import com.achobeta.domain.student.model.entity.StuResume;
+import com.achobeta.util.ObjectUtil;
import java.util.ArrayList;
-import java.util.Objects;
import java.util.function.Predicate;
/**
@@ -18,10 +18,7 @@ public class UserIdCondition extends ArrayList implements StudentCondition
@Override
public Predicate predicate() {
- return stuResume -> this
- .stream()
- .filter(Objects::nonNull)
- .anyMatch(userId -> userId.equals(stuResume.getUserId()))
- ;
+ return stuResume -> ObjectUtil.distinctNonNullStream(this)
+ .anyMatch(userId -> userId.equals(stuResume.getUserId()));
}
}
diff --git a/src/main/java/com/achobeta/domain/recruit/service/impl/ActivityParticipationServiceImpl.java b/src/main/java/com/achobeta/domain/recruit/service/impl/ActivityParticipationServiceImpl.java
index 67036178..247e3252 100644
--- a/src/main/java/com/achobeta/domain/recruit/service/impl/ActivityParticipationServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/recruit/service/impl/ActivityParticipationServiceImpl.java
@@ -14,6 +14,7 @@
import com.achobeta.redis.lock.RedisLock;
import com.achobeta.redis.lock.strategy.ReadLockStrategy;
import com.achobeta.redis.lock.strategy.SimpleLockStrategy;
+import com.achobeta.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -103,6 +104,7 @@ public List getParticipationIdsByPaperId(Long paperId) {
@Override
public List getParticipationPeriods(List participationIds) {
+ participationIds = ObjectUtil.distinctNonNullStream(participationIds).toList();
if(CollectionUtils.isEmpty(participationIds)) {
return new ArrayList<>();
}
@@ -111,6 +113,7 @@ public List getParticipationPeriods(List participat
@Override
public List getParticipationQuestions(List participationIds) {
+ participationIds = ObjectUtil.distinctNonNullStream(participationIds).toList();
if(CollectionUtils.isEmpty(participationIds)) {
return new ArrayList<>();
}
diff --git a/src/main/java/com/achobeta/domain/recruit/service/impl/ParticipationQuestionLinkServiceImpl.java b/src/main/java/com/achobeta/domain/recruit/service/impl/ParticipationQuestionLinkServiceImpl.java
index 32c0736e..463a4373 100644
--- a/src/main/java/com/achobeta/domain/recruit/service/impl/ParticipationQuestionLinkServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/recruit/service/impl/ParticipationQuestionLinkServiceImpl.java
@@ -15,7 +15,7 @@
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
-import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -76,7 +76,7 @@ public Optional getParticipationQuestionLink(Long par
@Override
public void putQuestionAnswers(Long participationId, List questionAnswerDTOS) {
Long recId = getActivityParticipationActId(participationId);
- Map hash = new HashMap<>();
+ Map hash = new LinkedHashMap<>();
// 获取答题模板
recruitmentActivityService.getQuestionsByActId(recId).forEach(questionVO -> {
hash.put(questionVO.getId(), ActivityParticipationConstants.DEFAULT_ANSWER);
diff --git a/src/main/java/com/achobeta/domain/resource/controller/ResourceController.java b/src/main/java/com/achobeta/domain/resource/controller/ResourceController.java
index 610c2988..f3453183 100644
--- a/src/main/java/com/achobeta/domain/resource/controller/ResourceController.java
+++ b/src/main/java/com/achobeta/domain/resource/controller/ResourceController.java
@@ -88,7 +88,6 @@ public SystemJsonResponse getLevels() {
}
@PostMapping("/upload/one")
- @Intercept(permit = {UserTypeEnum.ADMIN, UserTypeEnum.USER}, log = true)
public SystemJsonResponse upload(@RequestPart("file") MultipartFile file) {
Long userId = BaseContext.getCurrentUser().getUserId();
Long code = resourceService.upload(userId, file);
@@ -96,7 +95,7 @@ public SystemJsonResponse upload(@RequestPart("file") MultipartFile file) {
}
@PostMapping("/upload/syncfeishu/markdown")
- @Intercept(permit = {UserTypeEnum.ADMIN}, log = true)
+ @Intercept(permit = {UserTypeEnum.ADMIN})
public SystemJsonResponse uploadMarkdown(@RequestPart("file") MultipartFile file,
@RequestParam(name = "level", required = false) Integer level) {
ResourceUtil.checkText(MediaUtil.getContentType(file));
@@ -109,7 +108,7 @@ public SystemJsonResponse uploadMarkdown(@RequestPart("file") MultipartFile file
}
@PostMapping("/upload/syncfeishu/sheet")
- @Intercept(permit = {UserTypeEnum.ADMIN}, log = true)
+ @Intercept(permit = {UserTypeEnum.ADMIN})
public SystemJsonResponse uploadExcel(@RequestPart("file") MultipartFile file,
@RequestParam(name = "level", required = false) Integer level) {
ResourceUtil.checkSheet(MediaUtil.getBytes(file));
@@ -122,7 +121,6 @@ public SystemJsonResponse uploadExcel(@RequestPart("file") MultipartFile file,
}
@PostMapping("/upload/image")
- @Intercept(permit = {UserTypeEnum.ADMIN, UserTypeEnum.USER}, log = true)
public SystemJsonResponse uploadImage(@RequestPart("file") MultipartFile file) {
// 检查
ResourceUtil.checkImage(MediaUtil.getContentType(file));
@@ -132,7 +130,6 @@ public SystemJsonResponse uploadImage(@RequestPart("file") MultipartFile file) {
}
@PostMapping("/upload/video")
- @Intercept(permit = {UserTypeEnum.ADMIN, UserTypeEnum.USER}, log = true)
public SystemJsonResponse uploadVideo(@RequestPart("file") MultipartFile file) {
// 检查
ResourceUtil.checkVideo(MediaUtil.getContentType(file));
@@ -142,7 +139,6 @@ public SystemJsonResponse uploadVideo(@RequestPart("file") MultipartFile file) {
}
@PostMapping("/upload/list")
- @Intercept(permit = {UserTypeEnum.ADMIN, UserTypeEnum.USER}, log = true)
public SystemJsonResponse upload(@RequestPart("file") List fileList) {
Long userId = BaseContext.getCurrentUser().getUserId();
List codeList = resourceService.uploadList(userId, fileList);
diff --git a/src/main/java/com/achobeta/domain/resource/service/ResourceService.java b/src/main/java/com/achobeta/domain/resource/service/ResourceService.java
index cbb878f0..f44222bd 100644
--- a/src/main/java/com/achobeta/domain/resource/service/ResourceService.java
+++ b/src/main/java/com/achobeta/domain/resource/service/ResourceService.java
@@ -35,7 +35,7 @@ public interface ResourceService {
void checkImage(Long code);
- void checkAndRemoveImage(Long code, Long old);
+ Boolean shouldRemove(Long code, Long old);
String getSystemUrl(Long code);
diff --git a/src/main/java/com/achobeta/domain/resource/service/impl/ObjectStorageMinioServiceImpl.java b/src/main/java/com/achobeta/domain/resource/service/impl/ObjectStorageMinioServiceImpl.java
index d7a50673..0068d329 100644
--- a/src/main/java/com/achobeta/domain/resource/service/impl/ObjectStorageMinioServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/resource/service/impl/ObjectStorageMinioServiceImpl.java
@@ -112,7 +112,7 @@ public String compressImage(Long userId, String fileName) throws Exception {
// 压缩图片
bytes = MediaUtil.compressImage(bytes);
// 上传图片
- String uniqueFileName = ResourceUtil.getUniqueFileName(userId, "." + MediaUtil.COMPRESS_FORMAT_NAME);
+ String uniqueFileName = ResourceUtil.getUniqueFileName(userId, MediaUtil.COMPRESS_FORMAT_SUFFIX);
minioEngine.upload(uniqueFileName, bytes);
return uniqueFileName;
}
diff --git a/src/main/java/com/achobeta/domain/resource/service/impl/ResourceServiceImpl.java b/src/main/java/com/achobeta/domain/resource/service/impl/ResourceServiceImpl.java
index 92fb1877..70526148 100644
--- a/src/main/java/com/achobeta/domain/resource/service/impl/ResourceServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/resource/service/impl/ResourceServiceImpl.java
@@ -125,11 +125,12 @@ public void checkImage(Long code) {
@Override
@Transactional
- public void checkAndRemoveImage(Long code, Long old) {
+ public Boolean shouldRemove(Long code, Long old) {
if(!code.equals(old)) {
checkImage(code);
- removeKindly(old);
+ return Boolean.TRUE;
}
+ return Boolean.FALSE;
}
@Override
@@ -167,7 +168,7 @@ public Long upload(Long userId, String originalName, byte[] data, ResourceAccess
if(ResourceUtil.matchType(contentType, ResourceType.IMAGE) && compressionThreshold.compareTo(data.length) <= 0) {
// 压缩图片
data = MediaUtil.compressImage(data);
- suffix = "." + MediaUtil.COMPRESS_FORMAT_NAME;
+ suffix = MediaUtil.COMPRESS_FORMAT_SUFFIX;
originalName = ResourceUtil.changeSuffix(originalName, suffix);
} else {
// 使用原后缀
@@ -308,7 +309,7 @@ public void compressImage(Long code) throws Exception {
String compressImage = objectStorageService.compressImage(resource.getUserId(), resource.getFileName());
digitalResourceService.renameDigitalResource(
resource.getId(),
- ResourceUtil.changeExtension(resource.getOriginalName(), MediaUtil.COMPRESS_FORMAT_NAME),
+ ResourceUtil.changeSuffix(resource.getOriginalName(), MediaUtil.COMPRESS_FORMAT_SUFFIX),
compressImage
);
}
diff --git a/src/main/java/com/achobeta/domain/resumestate/controller/ResumeStateController.java b/src/main/java/com/achobeta/domain/resumestate/controller/ResumeStateController.java
index d8600e89..72fe08ec 100644
--- a/src/main/java/com/achobeta/domain/resumestate/controller/ResumeStateController.java
+++ b/src/main/java/com/achobeta/domain/resumestate/controller/ResumeStateController.java
@@ -73,7 +73,7 @@ public SystemJsonResponse executeEvent(@PathVariable("resumeId") @NotNull Long r
Long managerId = BaseContext.getCurrentUser().getUserId();
log.warn("管理员更新简历 {} 为 {} 状态", managerId, resumeStatus);
// 不相等则更新
- if(!currentStatus.equals(resumeStatus)) {
+ if(currentStatus != resumeStatus) {
resumeStateService.switchResumeState(resumeId, resumeStatus, ResumeEvent.NEXT);
}
return SystemJsonResponse.SYSTEM_SUCCESS();
diff --git a/src/main/java/com/achobeta/domain/resumestate/service/impl/ResumeStateServiceImpl.java b/src/main/java/com/achobeta/domain/resumestate/service/impl/ResumeStateServiceImpl.java
index b104da31..5238773e 100644
--- a/src/main/java/com/achobeta/domain/resumestate/service/impl/ResumeStateServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/resumestate/service/impl/ResumeStateServiceImpl.java
@@ -87,7 +87,7 @@ public List getProcessByResumeId(StuResume currentResume)
ResumeStatus currentStatus = currentResume.getStatus();
List statusProcesses = resumeStatusProcessService.getProcessByResumeId(resumeId);
// 如果没有节点或者最后一个节点不是当前状态,则推进到当前状态
- if(CollectionUtils.isEmpty(statusProcesses) || !currentStatus.equals(statusProcesses.getLast().getResumeStatus())) {
+ if(CollectionUtils.isEmpty(statusProcesses) || currentStatus != statusProcesses.getLast().getResumeStatus()) {
ResumeStatusProcess process = resumeStatusProcessService.createResumeStatusProcess(resumeId, currentStatus, ResumeEvent.NEXT);
statusProcesses.add(process);
}
diff --git a/src/main/java/com/achobeta/domain/schedule/controller/InterviewScheduleController.java b/src/main/java/com/achobeta/domain/schedule/controller/InterviewScheduleController.java
index fdc26819..8529a910 100644
--- a/src/main/java/com/achobeta/domain/schedule/controller/InterviewScheduleController.java
+++ b/src/main/java/com/achobeta/domain/schedule/controller/InterviewScheduleController.java
@@ -2,10 +2,10 @@
import com.achobeta.common.SystemJsonResponse;
import com.achobeta.common.annotation.Intercept;
+import com.achobeta.common.annotation.MobilePhone;
import com.achobeta.common.enums.UserTypeEnum;
import com.achobeta.domain.interview.model.dto.InterviewConditionDTO;
import com.achobeta.domain.interview.model.vo.InterviewReserveVO;
-import com.achobeta.domain.recruit.model.entity.RecruitmentActivity;
import com.achobeta.domain.recruit.service.ActivityParticipationService;
import com.achobeta.domain.recruit.service.RecruitmentActivityService;
import com.achobeta.domain.resource.constants.ResourceConstants;
@@ -13,9 +13,9 @@
import com.achobeta.domain.resource.model.vo.OnlineResourceVO;
import com.achobeta.domain.schedule.model.dto.ScheduleDTO;
import com.achobeta.domain.schedule.model.dto.ScheduleUpdateDTO;
+import com.achobeta.domain.schedule.model.dto.SituationQueryDTO;
import com.achobeta.domain.schedule.model.vo.ParticipationDetailVO;
import com.achobeta.domain.schedule.model.vo.ScheduleDetailVO;
-import com.achobeta.domain.schedule.model.vo.ScheduleResumeVO;
import com.achobeta.domain.schedule.model.vo.UserSituationVO;
import com.achobeta.domain.schedule.service.InterviewScheduleService;
import com.achobeta.domain.schedule.service.InterviewerService;
@@ -23,7 +23,6 @@
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
-import jakarta.validation.constraints.Pattern;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
@@ -116,42 +115,39 @@ public SystemJsonResponse getInterviewScheduleList(@Valid @RequestBody(required
// 检测
Long managerId = BaseContext.getCurrentUser().getUserId();
// 查询
- List interviewScheduleList = interviewScheduleService.getInterviewScheduleList(managerId, InterviewConditionDTO.of(interviewConditionDTO));
+ List interviewScheduleList = interviewScheduleService.getInterviewScheduleList(managerId, InterviewConditionDTO.of(interviewConditionDTO));
return SystemJsonResponse.SYSTEM_SUCCESS(interviewScheduleList);
}
@PostMapping("/list/all")
public SystemJsonResponse getInterviewScheduleListAll(@Valid @RequestBody(required = false) InterviewConditionDTO interviewConditionDTO) {
// 查询
- List interviewScheduleList = interviewScheduleService.getInterviewScheduleList(null, InterviewConditionDTO.of(interviewConditionDTO));
+ List interviewScheduleList = interviewScheduleService.getInterviewScheduleList(null, InterviewConditionDTO.of(interviewConditionDTO));
return SystemJsonResponse.SYSTEM_SUCCESS(interviewScheduleList);
}
/**
* 管理员查看用户参与和预约情况
*
- * @param actId
- * @return
*/
- @GetMapping("/situations/{actId}")
- public SystemJsonResponse getUserParticipationSituationByActId(@PathVariable("actId") @NotNull Long actId) {
+ @PostMapping("/situations")
+ public SystemJsonResponse querySituations(@Valid @RequestBody SituationQueryDTO situationQueryDTO) {
// 检测
- recruitmentActivityService.checkRecruitmentActivityExists(actId);
+ recruitmentActivityService.checkRecruitmentActivityExists(situationQueryDTO.getActId());
// 获取参与本次招新活动的所有用户参与和预约情况
- UserSituationVO situations = interviewScheduleService.getSituationsByActId(actId);
+ UserSituationVO situations = interviewScheduleService.querySituations(situationQueryDTO);
return SystemJsonResponse.SYSTEM_SUCCESS(situations);
}
- @GetMapping("/print/situations/{actId}")
- public SystemJsonResponse printUserParticipationSituationByActId(@PathVariable("actId") @NotNull Long actId,
- @RequestParam(name = "level", required = false) Integer level,
- @RequestParam(name = "synchronous", required = false) Boolean synchronous) {
+ @PostMapping("/print/situations")
+ public SystemJsonResponse printUserParticipationSituations(@Valid @RequestBody SituationQueryDTO situationQueryDTO,
+ @RequestParam(name = "level", required = false) Integer level,
+ @RequestParam(name = "synchronous", required = false) Boolean synchronous) {
// 检测
- RecruitmentActivity activity = recruitmentActivityService.checkAndGetRecruitmentActivity(actId);
ResourceAccessLevel accessLevel = Optional.ofNullable(level).map(ResourceAccessLevel::get).orElse(ResourceConstants.DEFAULT_EXCEL_ACCESS_LEVEL);
// 打印表格
Long managerId = BaseContext.getCurrentUser().getUserId();
- OnlineResourceVO onlineResourceVO = interviewScheduleService.printSituations(managerId, activity, accessLevel, synchronous);
+ OnlineResourceVO onlineResourceVO = interviewScheduleService.printSituations(managerId, situationQueryDTO, accessLevel, synchronous);
return SystemJsonResponse.SYSTEM_SUCCESS(onlineResourceVO);
}
@@ -176,7 +172,7 @@ public SystemJsonResponse getParticipationDetail(@PathVariable("participationId"
@GetMapping("/reserve/{scheduleId}")
public SystemJsonResponse interviewReserveApply(@PathVariable("scheduleId") @NotNull Long scheduleId,
@RequestParam("title") @NotBlank(message = "标题不能为空") String title,
- @RequestParam(name = "mobile", required = false) @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号非法") String mobile) {
+ @RequestParam(name = "mobile", required = false) @MobilePhone String mobile) {
// 检查
interviewScheduleService.checkInterviewScheduleExists(scheduleId);
// 当前管理员
diff --git a/src/main/java/com/achobeta/domain/schedule/model/dao/mapper/InterviewScheduleMapper.java b/src/main/java/com/achobeta/domain/schedule/model/dao/mapper/InterviewScheduleMapper.java
index e7b914b7..ab6b937c 100644
--- a/src/main/java/com/achobeta/domain/schedule/model/dao/mapper/InterviewScheduleMapper.java
+++ b/src/main/java/com/achobeta/domain/schedule/model/dao/mapper/InterviewScheduleMapper.java
@@ -1,10 +1,10 @@
package com.achobeta.domain.schedule.model.dao.mapper;
import com.achobeta.domain.interview.model.dto.InterviewConditionDTO;
+import com.achobeta.domain.schedule.model.dto.SituationQueryDTO;
import com.achobeta.domain.schedule.model.entity.InterviewSchedule;
import com.achobeta.domain.schedule.model.vo.ParticipationScheduleVO;
import com.achobeta.domain.schedule.model.vo.ScheduleDetailVO;
-import com.achobeta.domain.schedule.model.vo.ScheduleResumeVO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
@@ -18,9 +18,9 @@
*/
public interface InterviewScheduleMapper extends BaseMapper {
- List getInterviewScheduleList(@Param("managerId") Long managerId, @Param("condition") InterviewConditionDTO interviewConditionDTO);
+ List getInterviewScheduleList(@Param("managerId") Long managerId, @Param("condition") InterviewConditionDTO interviewConditionDTO);
- List getSituationsByActId(@Param("actId") Long actId);
+ List querySituations(@Param("condition") SituationQueryDTO situationQueryDTO);
ParticipationScheduleVO getSituationsByParticipationId(@Param("participationId") Long participationId);
diff --git a/src/main/java/com/achobeta/domain/schedule/model/dao/mapper/InterviewerMapper.java b/src/main/java/com/achobeta/domain/schedule/model/dao/mapper/InterviewerMapper.java
index b74aaf3c..e212940c 100644
--- a/src/main/java/com/achobeta/domain/schedule/model/dao/mapper/InterviewerMapper.java
+++ b/src/main/java/com/achobeta/domain/schedule/model/dao/mapper/InterviewerMapper.java
@@ -1,7 +1,11 @@
package com.achobeta.domain.schedule.model.dao.mapper;
import com.achobeta.domain.schedule.model.entity.Interviewer;
+import com.achobeta.domain.schedule.model.vo.ScheduleInterviewerVO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
/**
* @author 马拉圈
@@ -11,6 +15,9 @@
*/
public interface InterviewerMapper extends BaseMapper {
+ List getInterviewersByScheduleIds(@Param("scheduleIds") List scheduleIds);
+
+
}
diff --git a/src/main/java/com/achobeta/domain/schedule/model/dto/SituationQueryDTO.java b/src/main/java/com/achobeta/domain/schedule/model/dto/SituationQueryDTO.java
new file mode 100644
index 00000000..5c3dc36b
--- /dev/null
+++ b/src/main/java/com/achobeta/domain/schedule/model/dto/SituationQueryDTO.java
@@ -0,0 +1,28 @@
+package com.achobeta.domain.schedule.model.dto;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-15
+ * Time: 0:14
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class SituationQueryDTO {
+
+ @NotNull(message = "活动 id 不能为空")
+ private Long actId;
+
+// @NotEmpty(message = "状态列表不能为空")
+ private List statusList;
+
+}
diff --git a/src/main/java/com/achobeta/domain/schedule/model/vo/ScheduleInterviewerVO.java b/src/main/java/com/achobeta/domain/schedule/model/vo/ScheduleInterviewerVO.java
new file mode 100644
index 00000000..37e7ce36
--- /dev/null
+++ b/src/main/java/com/achobeta/domain/schedule/model/vo/ScheduleInterviewerVO.java
@@ -0,0 +1,19 @@
+package com.achobeta.domain.schedule.model.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-14
+ * Time: 16:20
+ */
+@Data
+public class ScheduleInterviewerVO extends ScheduleVO {
+
+ private List interviewerVOList;
+
+}
diff --git a/src/main/java/com/achobeta/domain/schedule/service/InterviewScheduleService.java b/src/main/java/com/achobeta/domain/schedule/service/InterviewScheduleService.java
index bcaa9514..4b6a3ff7 100644
--- a/src/main/java/com/achobeta/domain/schedule/service/InterviewScheduleService.java
+++ b/src/main/java/com/achobeta/domain/schedule/service/InterviewScheduleService.java
@@ -2,13 +2,12 @@
import com.achobeta.domain.interview.model.dto.InterviewConditionDTO;
import com.achobeta.domain.interview.model.vo.InterviewReserveVO;
-import com.achobeta.domain.recruit.model.entity.RecruitmentActivity;
import com.achobeta.domain.resource.enums.ResourceAccessLevel;
import com.achobeta.domain.resource.model.vo.OnlineResourceVO;
+import com.achobeta.domain.schedule.model.dto.SituationQueryDTO;
import com.achobeta.domain.schedule.model.entity.InterviewSchedule;
import com.achobeta.domain.schedule.model.vo.ParticipationDetailVO;
import com.achobeta.domain.schedule.model.vo.ScheduleDetailVO;
-import com.achobeta.domain.schedule.model.vo.ScheduleResumeVO;
import com.achobeta.domain.schedule.model.vo.UserSituationVO;
import com.baomidou.mybatisplus.extension.service.IService;
@@ -26,23 +25,31 @@ public interface InterviewScheduleService extends IService {
Optional getInterviewSchedule(Long scheduleId);
- List getInterviewScheduleList(Long managerId, InterviewConditionDTO interviewConditionDTO);
+ List getInterviewScheduleList(Long managerId, InterviewConditionDTO interviewConditionDTO);
/**
- * @param actId 活动 id
+ * @param situationQueryDTO 查询条件
* @return 学生们参与情况,每一个学生包括:
* 1. 学生的基础信息
* 2. 学生时间段选择情况
* 3. 学生面试预约情况
* 并统计各个时间段选中次数
*/
- UserSituationVO getSituationsByActId(Long actId);
+ UserSituationVO querySituations(SituationQueryDTO situationQueryDTO);
ScheduleDetailVO getInterviewScheduleDetail(Long scheduleId);
ParticipationDetailVO getDetailActivityParticipation(Long participationId);
- OnlineResourceVO printSituations(Long managerId, RecruitmentActivity activity, ResourceAccessLevel level, Boolean synchronous);
+ /**
+ * 打印参与情况为表格
+ * @param managerId 管理员 id
+ * @param situationQueryDTO 查询条件
+ * @param level 资源等级
+ * @param synchronous 是否同步飞书
+ * @return 链接
+ */
+ OnlineResourceVO printSituations(Long managerId, SituationQueryDTO situationQueryDTO, ResourceAccessLevel level, Boolean synchronous);
InterviewReserveVO interviewReserveApply(Long scheduleId, String title, String mobile);
diff --git a/src/main/java/com/achobeta/domain/schedule/service/InterviewerService.java b/src/main/java/com/achobeta/domain/schedule/service/InterviewerService.java
index 2955d89b..1176d0d7 100644
--- a/src/main/java/com/achobeta/domain/schedule/service/InterviewerService.java
+++ b/src/main/java/com/achobeta/domain/schedule/service/InterviewerService.java
@@ -1,6 +1,7 @@
package com.achobeta.domain.schedule.service;
import com.achobeta.domain.schedule.model.entity.Interviewer;
+import com.achobeta.domain.schedule.model.vo.ScheduleInterviewerVO;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
@@ -19,6 +20,8 @@ public interface InterviewerService extends IService {
List getInterviewersByScheduleId(Long scheduleId);
+ List getInterviewersByScheduleIds(List scheduleIds);
+
// 写入 ------------------------------------------
Long createInterviewer(Long managerId, Long scheduleId);
diff --git a/src/main/java/com/achobeta/domain/schedule/service/impl/InterviewScheduleServiceImpl.java b/src/main/java/com/achobeta/domain/schedule/service/impl/InterviewScheduleServiceImpl.java
index 50614fe4..faa76fea 100644
--- a/src/main/java/com/achobeta/domain/schedule/service/impl/InterviewScheduleServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/schedule/service/impl/InterviewScheduleServiceImpl.java
@@ -14,6 +14,7 @@
import com.achobeta.domain.recruit.model.vo.TimePeriodCountVO;
import com.achobeta.domain.recruit.model.vo.TimePeriodVO;
import com.achobeta.domain.recruit.service.ActivityParticipationService;
+import com.achobeta.domain.recruit.service.RecruitmentActivityService;
import com.achobeta.domain.recruit.service.TimePeriodService;
import com.achobeta.domain.resource.enums.ExcelTemplateEnum;
import com.achobeta.domain.resource.enums.ResourceAccessLevel;
@@ -21,6 +22,7 @@
import com.achobeta.domain.resource.service.ResourceService;
import com.achobeta.domain.schedule.model.converter.SituationConverter;
import com.achobeta.domain.schedule.model.dao.mapper.InterviewScheduleMapper;
+import com.achobeta.domain.schedule.model.dto.SituationQueryDTO;
import com.achobeta.domain.schedule.model.entity.InterviewSchedule;
import com.achobeta.domain.schedule.model.entity.Interviewer;
import com.achobeta.domain.schedule.model.vo.*;
@@ -29,6 +31,7 @@
import com.achobeta.exception.GlobalServiceException;
import com.achobeta.redis.lock.RedisLock;
import com.achobeta.redis.lock.strategy.SimpleLockStrategy;
+import com.achobeta.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lark.oapi.service.vc.v1.model.ApplyReserveRespBody;
import lombok.RequiredArgsConstructor;
@@ -57,6 +60,8 @@ public class InterviewScheduleServiceImpl extends ServiceImpl getInterviewSchedule(Long scheduleId) {
}
@Override
- public List getInterviewScheduleList(Long managerId, InterviewConditionDTO interviewConditionDTO) {
- return interviewScheduleMapper.getInterviewScheduleList(managerId, interviewConditionDTO);
+ public List getInterviewScheduleList(Long managerId, InterviewConditionDTO interviewConditionDTO) {
+ Map scheduleDetailVOMap = interviewScheduleMapper.getInterviewScheduleList(managerId, interviewConditionDTO).stream().collect(Collectors.toMap(
+ ScheduleDetailVO::getId,
+ scheduleDetailVO -> {
+ // 处理 MP 给枚举默认值的情况
+ List interviewVOList = scheduleDetailVO.getInterviewVOList().stream().filter(i -> Objects.nonNull(i.getId())).toList();
+ scheduleDetailVO.setInterviewVOList(interviewVOList);
+ return scheduleDetailVO;
+ },
+ (oldData, newData) -> newData
+ ));
+ List scheduleIds = new ArrayList<>(scheduleDetailVOMap.keySet());
+ interviewerService.getInterviewersByScheduleIds(scheduleIds).stream()
+ .filter(scheduleDetailVO -> scheduleDetailVOMap.containsKey(scheduleDetailVO.getId()))
+ .forEach(scheduleDetailVO -> {
+ scheduleDetailVOMap.get(scheduleDetailVO.getId()).setInterviewerVOList(scheduleDetailVO.getInterviewerVOList());
+ });
+ return scheduleDetailVOMap.values().stream()
+ .sorted(Comparator.comparingLong(s -> s.getStartTime().getTime()))
+ .toList();
}
/**
@@ -98,9 +121,9 @@ public List getInterviewScheduleList(Long managerId, Interview
* 4. 构造返回值返回
*/
@Override
- public UserSituationVO getSituationsByActId(Long actId) {
+ public UserSituationVO querySituations(SituationQueryDTO situationQueryDTO) {
// periodId --> 时间段计数器
- Map countMap = timePeriodService.getTimePeriodsByActId(actId)
+ Map countMap = timePeriodService.getTimePeriodsByActId(situationQueryDTO.getActId())
.stream()
.collect(Collectors.toMap(
TimePeriodVO::getId,
@@ -108,7 +131,9 @@ public UserSituationVO getSituationsByActId(Long actId) {
(oldData, newData) -> newData)
);
// participationId --> 用户预约情况
- Map userParticipationVOMap = interviewScheduleMapper.getSituationsByActId(actId)
+ List statusList = ObjectUtil.distinctNonNullStream(situationQueryDTO.getStatusList()).toList();
+ situationQueryDTO.setStatusList(statusList);
+ Map userParticipationVOMap = interviewScheduleMapper.querySituations(situationQueryDTO)
.stream()
.collect(Collectors.toMap(
ParticipationScheduleVO::getParticipationId,
@@ -181,10 +206,11 @@ public ParticipationDetailVO getDetailActivityParticipation(Long participationId
}
@Override
- public OnlineResourceVO printSituations(Long managerId, RecruitmentActivity activity, ResourceAccessLevel level, Boolean synchronous) {
+ public OnlineResourceVO printSituations(Long managerId, SituationQueryDTO situationQueryDTO, ResourceAccessLevel level, Boolean synchronous) {
+ RecruitmentActivity activity = recruitmentActivityService.checkAndGetRecruitmentActivity(situationQueryDTO.getActId());
// 构造数据
Map resultMap = new LinkedHashMap<>();
- getSituationsByActId(activity.getId()).getUserParticipationVOS().forEach(situation -> {
+ querySituations(situationQueryDTO).getUserParticipationVOS().forEach(situation -> {
ActivitySituationExcelTemplate activitySituationExcelTemplate = new ActivitySituationExcelTemplate();
activitySituationExcelTemplate.setTimePeriodVOS(situation.getTimePeriodVOS());
activitySituationExcelTemplate.setScheduleVOS(situation.getScheduleVOS());
@@ -209,6 +235,7 @@ public OnlineResourceVO printSituations(Long managerId, RecruitmentActivity acti
activity.getTitle(),
synchronous
);
+
}
@Override
diff --git a/src/main/java/com/achobeta/domain/schedule/service/impl/InterviewerServiceImpl.java b/src/main/java/com/achobeta/domain/schedule/service/impl/InterviewerServiceImpl.java
index bbe0e702..584d8c48 100644
--- a/src/main/java/com/achobeta/domain/schedule/service/impl/InterviewerServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/schedule/service/impl/InterviewerServiceImpl.java
@@ -3,12 +3,16 @@
import com.achobeta.common.enums.GlobalServiceStatusCode;
import com.achobeta.domain.schedule.model.dao.mapper.InterviewerMapper;
import com.achobeta.domain.schedule.model.entity.Interviewer;
+import com.achobeta.domain.schedule.model.vo.ScheduleInterviewerVO;
import com.achobeta.domain.schedule.service.InterviewerService;
import com.achobeta.exception.GlobalServiceException;
+import com.achobeta.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -22,6 +26,8 @@
public class InterviewerServiceImpl extends ServiceImpl
implements InterviewerService{
+ private final InterviewerMapper interviewerMapper;
+
@Override
public Optional getInterviewer(Long managerId, Long scheduleId) {
return this.lambdaQuery()
@@ -37,6 +43,15 @@ public List getInterviewersByScheduleId(Long scheduleId) {
.list();
}
+ @Override
+ public List getInterviewersByScheduleIds(List scheduleIds) {
+ scheduleIds = ObjectUtil.distinctNonNullStream(scheduleIds).toList();
+ if(CollectionUtils.isEmpty(scheduleIds)) {
+ return new ArrayList<>();
+ }
+ return interviewerMapper.getInterviewersByScheduleIds(scheduleIds);
+ }
+
@Override
public Long createInterviewer(Long managerId, Long scheduleId) {
return getInterviewer(managerId, scheduleId).orElseGet(() -> {
diff --git a/src/main/java/com/achobeta/domain/shortlink/controller/ShortLinkController.java b/src/main/java/com/achobeta/domain/shortlink/controller/ShortLinkController.java
index d5fb70c8..5f3d0b72 100644
--- a/src/main/java/com/achobeta/domain/shortlink/controller/ShortLinkController.java
+++ b/src/main/java/com/achobeta/domain/shortlink/controller/ShortLinkController.java
@@ -1,8 +1,8 @@
package com.achobeta.domain.shortlink.controller;
import com.achobeta.common.SystemJsonResponse;
+import com.achobeta.common.annotation.Accessible;
import com.achobeta.common.annotation.Intercept;
-import com.achobeta.common.annotation.IsAccessible;
import com.achobeta.common.enums.UserTypeEnum;
import com.achobeta.domain.shortlink.model.dto.ShortLinkQueryDTO;
import com.achobeta.domain.shortlink.model.vo.ShortLinkQueryVO;
@@ -51,7 +51,7 @@ public RedirectView getShortLink(@PathVariable("code") @NotBlank String code) {
*/
@PostMapping("/trans")
public SystemJsonResponse transferAndSaveShortLink(HttpServletRequest request,
- @RequestParam("url") @NotBlank @IsAccessible(message = "链接不可访问") String url) {
+ @RequestParam("url") @NotBlank @Accessible(message = "链接不可访问") String url) {
// 转化
String shortLinkURL = shortLinkService.transShortLinkURL(request, url);
log.info("原链接:{} -> 短链接:{}", url, shortLinkURL);
diff --git a/src/main/java/com/achobeta/domain/student/model/dto/StuSimpleResumeDTO.java b/src/main/java/com/achobeta/domain/student/model/dto/StuSimpleResumeDTO.java
index 59658c8a..7b90253f 100644
--- a/src/main/java/com/achobeta/domain/student/model/dto/StuSimpleResumeDTO.java
+++ b/src/main/java/com/achobeta/domain/student/model/dto/StuSimpleResumeDTO.java
@@ -1,6 +1,7 @@
package com.achobeta.domain.student.model.dto;
import com.achobeta.common.annotation.IntRange;
+import com.achobeta.common.annotation.MobilePhone;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
@@ -45,7 +46,7 @@ public class StuSimpleResumeDTO implements Serializable {
private String email;
@NotBlank(message = "手机号不能为空")
- @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号非法")
+ @MobilePhone
private String phoneNumber;
@NotBlank(message = "加入ab理由不能为空")
diff --git a/src/main/java/com/achobeta/domain/student/service/impl/StuResumeServiceImpl.java b/src/main/java/com/achobeta/domain/student/service/impl/StuResumeServiceImpl.java
index 4360213f..673bce5d 100644
--- a/src/main/java/com/achobeta/domain/student/service/impl/StuResumeServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/student/service/impl/StuResumeServiceImpl.java
@@ -18,6 +18,7 @@
import com.achobeta.exception.GlobalServiceException;
import com.achobeta.redis.lock.RedisLock;
import com.achobeta.redis.lock.strategy.SimpleLockStrategy;
+import com.achobeta.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -80,7 +81,8 @@ public void submitResume(StuResumeDTO stuResumeDTO, Long userId) {
StuSimpleResumeDTO resumeDTO = stuResumeDTO.getStuSimpleResumeDTO();
// 检测
- resourceService.checkAndRemoveImage(resumeDTO.getImage(), stuResume.getImage());
+ Long oldImage = stuResume.getImage();
+ Boolean shouldRemove = resourceService.shouldRemove(resumeDTO.getImage(), oldImage);
//附件列表
List stuAttachmentDTOList = stuResumeDTO.getStuAttachmentDTOList();
@@ -91,6 +93,11 @@ public void submitResume(StuResumeDTO stuResumeDTO, Long userId) {
//保存附件信息
saveStuAttachment(stuAttachmentDTOList, stuResume.getId());
+
+ // 等提交成功后再删除
+ if(Boolean.TRUE.equals(shouldRemove)) {
+ resourceService.removeKindly(oldImage);
+ }
}, () -> {}, simpleLockStrategy);
}
@@ -152,7 +159,7 @@ private StuResume getStuResume(QueryResumeDTO queryResumeDTO) {
@Transactional
public void updateResumeInfo(StuResume stuResume, StuSimpleResumeDTO resumeDTO) {
ResumeStatus resumeStatus = stuResume.getStatus();
- if (Objects.isNull(resumeStatus) || ResumeStatus.DRAFT.equals(resumeStatus)) {
+ if (Objects.isNull(resumeStatus) || ResumeStatus.DRAFT == resumeStatus) {
//简历状态若为草稿则更新为待筛选
stuResume.setStatus(ResumeStatus.PENDING_SELECTION);
// 添加一个简历过程节点
@@ -230,6 +237,10 @@ public StuResume checkResumeSubmitCount(StuSimpleResumeDTO resumeDTO, Long userI
@Override
public List queryStuList(Long batchId, List userIds) {
+ userIds = ObjectUtil.distinctNonNullStream(userIds).toList();
+ if(CollectionUtils.isEmpty(userIds)) {
+ return new ArrayList<>();
+ }
return lambdaQuery()
.eq(StuResume::getBatchId, batchId)
.in(StuResume::getUserId, userIds)
diff --git a/src/main/java/com/achobeta/domain/users/service/impl/MemberServiceImpl.java b/src/main/java/com/achobeta/domain/users/service/impl/MemberServiceImpl.java
index 2691a82f..fe6da17b 100644
--- a/src/main/java/com/achobeta/domain/users/service/impl/MemberServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/users/service/impl/MemberServiceImpl.java
@@ -90,6 +90,7 @@ public List queryMemberList(Long batchId) {
return memberMapper.queryMemberList(batchId)
.stream()
.peek(member -> {
+ // 处理 MP 给枚举设置默认值的现象
if(Objects.isNull(member.getId())) {
member.setSimpleStudentVO(null);
}
diff --git a/src/main/java/com/achobeta/domain/users/service/impl/UserServiceImpl.java b/src/main/java/com/achobeta/domain/users/service/impl/UserServiceImpl.java
index 88421b44..8ec37b3d 100644
--- a/src/main/java/com/achobeta/domain/users/service/impl/UserServiceImpl.java
+++ b/src/main/java/com/achobeta/domain/users/service/impl/UserServiceImpl.java
@@ -56,12 +56,15 @@ public void updateUser(Long userId, UserDTO userDTO) {
// 设置默认头像
Long avatar = userDTO.getAvatar();
UserEntity userEntity = UserConverter.INSTANCE.userDTOToUser(userDTO);
- getUserById(userId).map(UserEntity::getAvatar).ifPresent(code -> {
- resourceService.checkAndRemoveImage(avatar, code);
- });
+ Long oldAvatar = getUserById(userId).map(UserEntity::getAvatar).orElse(null);
+ Boolean shouldRemove = resourceService.shouldRemove(avatar, oldAvatar);
// 更新
this.lambdaUpdate()
.eq(UserEntity::getId, userId)
.update(userEntity);
+ // 更新成功再删除
+ if(Boolean.TRUE.equals(shouldRemove)) {
+ resourceService.removeKindly(oldAvatar);
+ }
}
}
diff --git a/src/main/java/com/achobeta/email/provider/EmailSenderProvider.java b/src/main/java/com/achobeta/email/provider/EmailSenderProvider.java
index c2942f63..fcff7b6c 100644
--- a/src/main/java/com/achobeta/email/provider/EmailSenderProvider.java
+++ b/src/main/java/com/achobeta/email/provider/EmailSenderProvider.java
@@ -3,18 +3,16 @@
import cn.hutool.extra.spring.SpringUtil;
import com.achobeta.common.enums.GlobalServiceStatusCode;
import com.achobeta.email.config.EmailSenderConfig;
-import com.achobeta.email.config.EmailSenderProperties;
import com.achobeta.email.provider.strategy.ProvideStrategy;
import com.achobeta.exception.GlobalServiceException;
+import com.achobeta.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
-import java.util.ArrayList;
import java.util.List;
-import java.util.Optional;
/**
* Created With Intellij IDEA
@@ -36,9 +34,7 @@ public class EmailSenderProvider implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// 构造邮件发送器实现
- this.senderList = new ArrayList<>();
- List senders = emailSenderConfig.getSenders();
- Optional.ofNullable(senders).stream().flatMap(List::stream).forEach(sender -> {
+ this.senderList = ObjectUtil.distinctNonNullStream(emailSenderConfig.getSenders()).map(sender -> {
// 邮件发送者
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(sender.getHost());
@@ -48,8 +44,8 @@ public void afterPropertiesSet() throws Exception {
javaMailSender.setProtocol(sender.getProtocol());
javaMailSender.setDefaultEncoding(sender.getDefaultEncoding());
javaMailSender.setJavaMailProperties(sender.getProperties());
- senderList.add(javaMailSender);
- });
+ return javaMailSender;
+ }).toList();
// 若不存在一个实现则抛出异常(启动项目时)
if(CollectionUtils.isEmpty(this.senderList)) {
throw new GlobalServiceException(GlobalServiceStatusCode.EMAIL_SENDER_NOT_EXISTS);
diff --git a/src/main/java/com/achobeta/feishu/aspect/FeishuRequestAspect.java b/src/main/java/com/achobeta/feishu/aspect/FeishuRequestAspect.java
index af0b5168..68a26571 100644
--- a/src/main/java/com/achobeta/feishu/aspect/FeishuRequestAspect.java
+++ b/src/main/java/com/achobeta/feishu/aspect/FeishuRequestAspect.java
@@ -2,7 +2,7 @@
import com.achobeta.common.enums.GlobalServiceStatusCode;
import com.achobeta.exception.GlobalServiceException;
-import com.achobeta.feishu.token.FeishuTenantAccessToken;
+import com.achobeta.feishu.token.FeishuTenantSession;
import com.lark.oapi.core.response.BaseResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -24,7 +24,7 @@
@RequiredArgsConstructor
public class FeishuRequestAspect {
- private final FeishuTenantAccessToken feishuTenantAccessToken;
+ private final FeishuTenantSession feishuTenantSession;
// 虽然不排除没有返回值的情况,idea 插件识别切点目标方法里没有无返回值的目标方法,但实际上无返回值的目标方法也会执行 AfterReturning,result 为 null 罢了
// 所以要专门排除!
@@ -41,7 +41,7 @@ public void doAfterReturning(Object result) {
log.info("飞书请求成功");
} else {
log.info("飞书 token 刷新");
- feishuTenantAccessToken.refreshToken();
+ feishuTenantSession.refreshToken();
throw new GlobalServiceException(response.getMsg(), GlobalServiceStatusCode.REQUEST_NOT_VALID);
}
}else {
diff --git a/src/main/java/com/achobeta/feishu/token/FeishuTenantAccessToken.java b/src/main/java/com/achobeta/feishu/token/FeishuTenantSession.java
similarity index 98%
rename from src/main/java/com/achobeta/feishu/token/FeishuTenantAccessToken.java
rename to src/main/java/com/achobeta/feishu/token/FeishuTenantSession.java
index 43523eb0..50d04f79 100644
--- a/src/main/java/com/achobeta/feishu/token/FeishuTenantAccessToken.java
+++ b/src/main/java/com/achobeta/feishu/token/FeishuTenantSession.java
@@ -20,7 +20,7 @@
*/
@Component
@RequiredArgsConstructor
-public class FeishuTenantAccessToken {
+public class FeishuTenantSession {
private final Client feishuClient;
diff --git a/src/main/java/com/achobeta/handler/GlobalExceptionHandler.java b/src/main/java/com/achobeta/handler/GlobalExceptionHandler.java
index 35527199..32f29484 100644
--- a/src/main/java/com/achobeta/handler/GlobalExceptionHandler.java
+++ b/src/main/java/com/achobeta/handler/GlobalExceptionHandler.java
@@ -1,12 +1,14 @@
package com.achobeta.handler;
import com.achobeta.common.SystemJsonResponse;
-import com.achobeta.common.enums.GlobalServiceStatusCode;
+import com.achobeta.config.RequestIdConfig;
import com.achobeta.exception.GlobalServiceException;
import com.mysql.jdbc.MysqlDataTruncation;
import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.springframework.dao.DataIntegrityViolationException;
@@ -32,38 +34,43 @@
*/
@Slf4j
@RestControllerAdvice
+@RequiredArgsConstructor
public class GlobalExceptionHandler {
+ private final RequestIdConfig requestIdConfig;
+
+ private void logError(HttpServletRequest request, HttpServletResponse response, Exception e) {
+ log.error("请求 {} 访问接口 {},错误信息 {}",
+ response.getHeader(requestIdConfig.getHeader()),
+ request.getRequestURI(),
+ e.getMessage()
+ );
+ }
+
@ExceptionHandler(GlobalServiceException.class)
- public SystemJsonResponse handleGlobalServiceException(GlobalServiceException e, HttpServletRequest request) {
- String requestURI = request.getRequestURI();
- String message = e.getMessage();
- GlobalServiceStatusCode statusCode = e.getStatusCode();
- log.error("请求地址'{}', {}: '{}'", requestURI, statusCode, message);
- return SystemJsonResponse.CUSTOMIZE_MSG_ERROR(statusCode, message);
+ public SystemJsonResponse handleGlobalServiceException(GlobalServiceException e, HttpServletRequest request, HttpServletResponse response) {
+ logError(request, response, e);
+ return SystemJsonResponse.CUSTOMIZE_MSG_ERROR(e.getStatusCode(), e.getMessage());
}
@ExceptionHandler({FileUploadException.class})
- public SystemJsonResponse handleFileUploadException(FileUploadException e, HttpServletRequest request) {
- String requestURI = request.getRequestURI();
- String message = e.getMessage();
- log.error("请求地址'{}', '{}'", requestURI, message);
+ public SystemJsonResponse handleFileUploadException(FileUploadException e, HttpServletRequest request, HttpServletResponse response) {
+ logError(request, response, e);
+ String message = "文件上传异常";
return SystemJsonResponse.CUSTOMIZE_MSG_ERROR(RESOURCE_NOT_VALID, message);
}
@ExceptionHandler({DataIntegrityViolationException.class})
- public SystemJsonResponse handleDataIntegrityViolationException(DataIntegrityViolationException e, HttpServletRequest request) {
- String requestURI = request.getRequestURI();
- String message = e.getCause() instanceof MysqlDataTruncation ? "文本长度超出限制" : "数据异常";
- log.error("请求地址'{}', '{}', '{}'", requestURI, message, e.getMessage());
+ public SystemJsonResponse handleDataIntegrityViolationException(DataIntegrityViolationException e, HttpServletRequest request, HttpServletResponse response) {
+ logError(request, response, e);
+ String message = e.getCause() instanceof MysqlDataTruncation ? "数据截断,请检查长度、范围和类型" : "数据非法";
return SystemJsonResponse.CUSTOMIZE_MSG_ERROR(SYSTEM_SERVICE_ERROR, message);
}
@ExceptionHandler({SQLException.class})
- public SystemJsonResponse handleSQLException(SQLException e, HttpServletRequest request) {
- String requestURI = request.getRequestURI();
- String message = "数据异常";
- log.error("请求地址'{}', '{}', '{}'", requestURI, message, e.getMessage());
+ public SystemJsonResponse handleSQLException(SQLException e, HttpServletRequest request, HttpServletResponse response) {
+ logError(request, response, e);
+ String message = "数据访问与交互异常";
return SystemJsonResponse.CUSTOMIZE_MSG_ERROR(SYSTEM_SERVICE_ERROR, message);
}
@@ -71,9 +78,8 @@ public SystemJsonResponse handleSQLException(SQLException e, HttpServletRequest
* 自定义验证异常
*/
@ExceptionHandler(ConstraintViolationException.class)
- public SystemJsonResponse constraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
- String requestURI = request.getRequestURI();
- log.error("请求地址'{}', 自定义验证异常'{}'", requestURI, e.getMessage());
+ public SystemJsonResponse constraintViolationException(ConstraintViolationException e, HttpServletRequest request, HttpServletResponse response) {
+ logError(request, response, e);
String message = e.getConstraintViolations().stream()
.map(ConstraintViolation::getMessage)
.filter(Objects::nonNull)
@@ -82,9 +88,8 @@ public SystemJsonResponse constraintViolationException(ConstraintViolationExcept
}
@ExceptionHandler(MethodArgumentNotValidException.class)
- public SystemJsonResponse ValidationHandler(MethodArgumentNotValidException e, HttpServletRequest request) {
- String requestURI = request.getRequestURI();
- log.error("请求地址'{}', 自定义验证异常'{}'", requestURI, e.getMessage());
+ public SystemJsonResponse ValidationHandler(MethodArgumentNotValidException e, HttpServletRequest request, HttpServletResponse response) {
+ logError(request, response, e);
String message = e.getBindingResult().getFieldErrors().stream()
.map(FieldError::getDefaultMessage)
.filter(Objects::nonNull)
diff --git a/src/main/java/com/achobeta/interceptor/UserInterceptor.java b/src/main/java/com/achobeta/interceptor/UserInterceptor.java
index f8222a62..7e5518d9 100644
--- a/src/main/java/com/achobeta/interceptor/UserInterceptor.java
+++ b/src/main/java/com/achobeta/interceptor/UserInterceptor.java
@@ -88,15 +88,16 @@ public UserHelper getUserHelper() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+ // 设置请求 id
+ long requestId = requestIdGenerator.nextId();
+ response.setHeader(requestIdConfig.getHeader(), String.valueOf(requestId));
+
//可以解决拦截器跨域问题
if (!(handler instanceof HandlerMethod)) {
// 并不处理非目标方法的请求
// todo: 例如通过本服务,但不是通过目标方法获取资源的请求,而这些请求需要进行其他的处理!
return Boolean.TRUE;
}
- // 设置请求 id
- long requestId = requestIdGenerator.nextId();
- response.setHeader(requestIdConfig.getHeader(), String.valueOf(requestId));
// 获取目标方法
Method targetMethod = ((HandlerMethod) handler).getMethod();
// 获取 intercept 注解实例
@@ -123,17 +124,11 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
try {
- if(handler instanceof HandlerMethod handlerMethod) {
- // 获取目标方法
- Method targetMethod = handlerMethod.getMethod();
- if(InterceptHelper.shouldPrintLog(targetMethod)) {
- String requestId = response.getHeader(requestIdConfig.getHeader());
- log.warn("请求 {} 访问接口 {},响应 HTTP 状态码 {},错误信息 {}",
- requestId, request.getRequestURI(), response.getStatus(),
- Optional.ofNullable(ex).map(Exception::getMessage).orElse(null)
- );
- }
- }
+ String requestId = response.getHeader(requestIdConfig.getHeader());
+ log.warn("请求 {} 访问接口 {},响应 HTTP 状态码 {},错误信息 {}",
+ requestId, request.getRequestURI(), response.getStatus(),
+ Optional.ofNullable(ex).map(Exception::getMessage).orElse(null)
+ );
} finally {
log.info("删除本地线程变量");
BaseContext.removeCurrentUser();
diff --git a/src/main/java/com/achobeta/template/engine/HtmlEngine.java b/src/main/java/com/achobeta/template/engine/HtmlEngine.java
index 74a6bcc5..31376695 100644
--- a/src/main/java/com/achobeta/template/engine/HtmlEngine.java
+++ b/src/main/java/com/achobeta/template/engine/HtmlEngine.java
@@ -2,14 +2,8 @@
import com.achobeta.template.model.po.ReplaceResource;
import com.achobeta.template.model.po.Resource;
+import com.achobeta.template.util.MarkdownUtil;
import com.achobeta.template.util.TemplateUtil;
-import com.vladsch.flexmark.ext.tables.TablesExtension;
-import com.vladsch.flexmark.ext.toc.TocExtension;
-import com.vladsch.flexmark.html.HtmlRenderer;
-import com.vladsch.flexmark.parser.Parser;
-import com.vladsch.flexmark.parser.ParserEmulationProfile;
-import com.vladsch.flexmark.util.ast.Node;
-import com.vladsch.flexmark.util.data.MutableDataSet;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
@@ -41,29 +35,6 @@ public HtmlBuilder builder() {
public class HtmlBuilder {
- private final static MutableDataSet OPTIONS;
-
- private final static Parser PARSER;
-
- private final static HtmlRenderer HTML_RENDERER;
-
- static {
- OPTIONS = new MutableDataSet()
- .setFrom(ParserEmulationProfile.MARKDOWN)
- // 支持 [TOC]目录 以及 表格
- .set(Parser.EXTENSIONS, List.of(TocExtension.create(), TablesExtension.create()))
- ;
- PARSER = Parser.builder(OPTIONS).build();
- HTML_RENDERER = HtmlRenderer.builder(OPTIONS).build();
- }
-
- private String markdownToHtml(String markdown) {
- // 解析 Markdown 文本为节点
- Node document = PARSER.parse(markdown);
- // 将 Markdown 节点渲染为 HTML
- return HTML_RENDERER.render(document);
- }
-
private final StringBuffer htmlBuffer = new StringBuffer();
public String build() {
@@ -104,7 +75,7 @@ public HtmlBuilder append(List resourceList) {
// md -> html 追加
public HtmlBuilder appendMarkdown(String markdown) {
- String html = markdownToHtml(markdown);
+ String html = MarkdownUtil.markdownToHtml(markdown);
return append(html);
}
@@ -156,7 +127,7 @@ public HtmlBuilder replace(List resourceList) {
* 3. 紧接着调用 replaceMarkdown,传入 uniqueSymbol 和原 markdown 文本,文本转换为 html 并替换 uniqueSymbol 的位置
*/
public HtmlBuilder replaceMarkdown(String target, String markdown) {
- String html = markdownToHtml(markdown);
+ String html = MarkdownUtil.markdownToHtml(markdown);
return replace(target, html);
}
@@ -167,7 +138,7 @@ public HtmlBuilder replaceMarkdown(ReplaceResource resource) {
// md 转化为 html 替换对应的 target
public HtmlBuilder replaceMarkdown(List resourceList) {
- String finalHtml = TemplateUtil.replaceSafely(build(), resourceList, this::markdownToHtml);
+ String finalHtml = TemplateUtil.replaceSafely(build(), resourceList, MarkdownUtil::markdownToHtml);
return reset(finalHtml);
}
diff --git a/src/main/java/com/achobeta/template/util/MarkdownUtil.java b/src/main/java/com/achobeta/template/util/MarkdownUtil.java
new file mode 100644
index 00000000..cbcf394b
--- /dev/null
+++ b/src/main/java/com/achobeta/template/util/MarkdownUtil.java
@@ -0,0 +1,108 @@
+package com.achobeta.template.util;
+
+
+import com.vladsch.flexmark.ext.abbreviation.AbbreviationExtension;
+import com.vladsch.flexmark.ext.admonition.AdmonitionExtension;
+import com.vladsch.flexmark.ext.anchorlink.AnchorLinkExtension;
+import com.vladsch.flexmark.ext.aside.AsideExtension;
+import com.vladsch.flexmark.ext.definition.DefinitionExtension;
+import com.vladsch.flexmark.ext.emoji.EmojiExtension;
+import com.vladsch.flexmark.ext.footnotes.FootnoteExtension;
+import com.vladsch.flexmark.ext.gfm.issues.GfmIssuesExtension;
+import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughSubscriptExtension;
+import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension;
+import com.vladsch.flexmark.ext.gfm.users.GfmUsersExtension;
+import com.vladsch.flexmark.ext.gitlab.GitLabExtension;
+import com.vladsch.flexmark.ext.ins.InsExtension;
+import com.vladsch.flexmark.ext.media.tags.MediaTagsExtension;
+import com.vladsch.flexmark.ext.resizable.image.ResizableImageExtension;
+import com.vladsch.flexmark.ext.superscript.SuperscriptExtension;
+import com.vladsch.flexmark.ext.tables.TablesExtension;
+import com.vladsch.flexmark.ext.toc.TocExtension;
+import com.vladsch.flexmark.ext.typographic.TypographicExtension;
+import com.vladsch.flexmark.ext.wikilink.WikiLinkExtension;
+import com.vladsch.flexmark.formatter.Formatter;
+import com.vladsch.flexmark.html.HtmlRenderer;
+import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
+import com.vladsch.flexmark.parser.Parser;
+import com.vladsch.flexmark.parser.ParserEmulationProfile;
+import com.vladsch.flexmark.util.ast.Node;
+import com.vladsch.flexmark.util.data.MutableDataSet;
+
+import java.util.Arrays;
+
+/**
+ * Created With Intellij IDEA
+ * Description:
+ * User: 马拉圈
+ * Date: 2024-10-17
+ * Time: 11:16
+ */
+public class MarkdownUtil {
+
+ private final static MutableDataSet OPTIONS;
+
+ private final static Parser PARSER;
+
+ private final static HtmlRenderer HTML_RENDERER;
+
+ private final static FlexmarkHtmlConverter HTML_CONVERTER;
+
+ private final static Formatter MARKDOWN_FORMATTER;
+
+ static {
+ OPTIONS = new MutableDataSet()
+ // 指定 Markdown 标准为 COMMONMARK(使用 ParserEmulationProfile.MARKDOWN 可能会有一些语法失效!)
+ .setFrom(ParserEmulationProfile.COMMONMARK)
+ .set(Parser.EXTENSIONS, Arrays.asList(new Parser.ParserExtension[]{
+ // 设置一些常扩展
+ TocExtension.create(),
+ TablesExtension.create(),
+ AbbreviationExtension.create(),
+// AutolinkExtension.create(),
+ AnchorLinkExtension.create(),
+ AsideExtension.create(),
+ AdmonitionExtension.create(),
+ GfmIssuesExtension.create(),
+ GfmUsersExtension.create(),
+ SuperscriptExtension.create(),
+ StrikethroughSubscriptExtension.create(),
+ GitLabExtension.create(),
+ FootnoteExtension.create(),
+ TaskListExtension.create(),
+ InsExtension.create(),
+ TypographicExtension.create(),
+ DefinitionExtension.create(),
+ AbbreviationExtension.create(),
+ ResizableImageExtension.create(),
+ MediaTagsExtension.create(),
+ EmojiExtension.create(),
+ WikiLinkExtension.create(),
+ })).set(HtmlRenderer.SOFT_BREAK, "
\n");
+ PARSER = Parser.builder(OPTIONS).build();
+ HTML_RENDERER = HtmlRenderer.builder(OPTIONS).build();
+ HTML_CONVERTER = FlexmarkHtmlConverter.builder(OPTIONS).build();
+ MARKDOWN_FORMATTER = Formatter.builder(OPTIONS).build();
+ }
+
+ public static String markdownToHtml(String markdown) {
+ // 解析 Markdown 文本为节点
+ Node document = PARSER.parse(markdown);
+ // 将 Markdown 节点渲染为 HTML
+ return HTML_RENDERER.render(document);
+ }
+
+ public static String htmlToMarkdown(String html) {
+ // 将 HTML 转化为 Markdown
+ return HTML_CONVERTER.convert(html);
+ }
+
+ public static String markdownPrettyUp(String markdown) {
+
+ // 解析 Markdown 文本为节点
+ Node document = PARSER.parse(markdown);
+ // 格式化 Markdown
+ return MARKDOWN_FORMATTER.render(document);
+ }
+
+}
diff --git a/src/main/java/com/achobeta/util/HttpRequestUtil.java b/src/main/java/com/achobeta/util/HttpRequestUtil.java
index 3f4b8664..4888050b 100644
--- a/src/main/java/com/achobeta/util/HttpRequestUtil.java
+++ b/src/main/java/com/achobeta/util/HttpRequestUtil.java
@@ -1,9 +1,11 @@
package com.achobeta.util;
import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.achobeta.common.enums.HttpRequestEnum;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.StringUtils;
@@ -22,17 +24,20 @@
/**
* Created With Intellij IDEA
- * Description:
* User: 马拉圈
* Date: 2024-09-26
* Time: 7:41
+ * Description: 用 Gson 序列化,已有业务依赖 Gson,不建议修改为其他序列化器
*/
+@Slf4j
public class HttpRequestUtil {
public final static Map JSON_CONTENT_TYPE_HEADER = Map.of(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8");
public static final Pattern HTTP_URL_PATTERN = Pattern.compile("^(?i)(http|https):(//(([^@\\[/?#]*)@)?(\\[[\\p{XDigit}:.]*[%\\p{Alnum}]*]|[^\\[/?#:]*)(:(\\{[^}]+\\}?|[^/?#]*))?)?([^?#]*)(\\?([^#]*))?(#(.*))?");
+ private static final int MAX_REDIRECT_COUNT = 10;
+
public static boolean isHttpUrl(String url) {
return StringUtils.hasText(url) && HTTP_URL_PATTERN.matcher(url).matches();
}
@@ -41,7 +46,19 @@ public static boolean isAccessible(HttpURLConnection connection) throws IOExcept
return Objects.nonNull(connection) && connection.getResponseCode() / 100 == 2;
}
+ public static boolean isAccessible(HttpResponse response) throws IOException {
+ return Objects.nonNull(response) && response.getStatus() / 100 == 2;
+ }
+
public static boolean isAccessible(String url) throws IOException {
+ // 尝试两种方式去校验
+ try {
+ if(isAccessible(getRequestAndExecute(url))) {
+ return Boolean.TRUE;
+ }
+ } catch (Exception e) {
+ log.warn(e.getMessage());
+ }
return isAccessible(openConnection(url));
}
@@ -54,6 +71,19 @@ public static HttpURLConnection openConnection(String url) throws IOException {
}
}
+ public static HttpResponse getRequestAndExecute(String url) {
+ return getRequestAndExecute(url, 1);
+ }
+
+ public static HttpResponse getRequestAndExecute(String url, int count) {
+ HttpResponse response = isHttpUrl(url) ? HttpUtil.createRequest(Method.GET, url).execute() : null;
+ if(Objects.nonNull(response) && response.getStatus() / 100 == 3 && count <= MAX_REDIRECT_COUNT) {
+ return getRequestAndExecute(response.header("Location"), count + 1); // Location 就是最深的那个地址了
+ } else {
+ return response;
+ }
+ }
+
public static String hiddenQueryString(String url) {
return StringUtils.hasText(url) && url.contains("?") ? url.substring(0, url.indexOf("?")) : url;
}
diff --git a/src/main/java/com/achobeta/util/HttpServletUtil.java b/src/main/java/com/achobeta/util/HttpServletUtil.java
index 52b0134a..8056a793 100644
--- a/src/main/java/com/achobeta/util/HttpServletUtil.java
+++ b/src/main/java/com/achobeta/util/HttpServletUtil.java
@@ -29,10 +29,16 @@ public static Optional getAttributes() {
return Optional.ofNullable((ServletRequestAttributes) RequestContextHolder.getRequestAttributes());
}
+ /**
+ * 获取本次请求的 HttpServletRequest 对象
+ */
public static HttpServletRequest getRequest() {
return getAttributes().map(ServletRequestAttributes::getRequest).orElseThrow(GlobalServiceException::new);
}
+ /**
+ * 获取本次请求的 HttpServletResponse 对象
+ */
public static HttpServletResponse getResponse() {
return getAttributes().map(ServletRequestAttributes::getResponse).orElseThrow(GlobalServiceException::new);
}
diff --git a/src/main/java/com/achobeta/util/MediaUtil.java b/src/main/java/com/achobeta/util/MediaUtil.java
index a6b6d4a7..335a83e1 100644
--- a/src/main/java/com/achobeta/util/MediaUtil.java
+++ b/src/main/java/com/achobeta/util/MediaUtil.java
@@ -1,5 +1,6 @@
package com.achobeta.util;
+import cn.hutool.http.HttpResponse;
import com.achobeta.common.enums.GlobalServiceStatusCode;
import com.achobeta.exception.GlobalServiceException;
import lombok.extern.slf4j.Slf4j;
@@ -27,6 +28,8 @@ public class MediaUtil {
public final static String COMPRESS_FORMAT_NAME = "jpg"; // 压缩图片格式
+ public final static String COMPRESS_FORMAT_SUFFIX = "." + COMPRESS_FORMAT_NAME; // 压缩图片格式
+
public final static float COMPRESS_SCALE = 1.0f; // 压缩图片大小
public final static float COMPRESS_QUALITY = 0.5f; // 压缩图片质量
@@ -49,6 +52,16 @@ public static byte[] compressImage(byte[] bytes) {
}
public static InputStream getInputStream(String url) throws IOException {
+ // 尝试两次去获取
+ try {
+ HttpResponse response = HttpRequestUtil.getRequestAndExecute(url);
+ InputStream inputStream = HttpRequestUtil.isAccessible(response) ? response.bodyStream() : null;
+ if(Objects.nonNull(inputStream)) {
+ return inputStream;
+ }
+ } catch (Exception e) {
+ log.warn(e.getMessage());
+ }
HttpURLConnection connection = HttpRequestUtil.openConnection(url);
return HttpRequestUtil.isAccessible(connection) ? connection.getInputStream() : null;
}
diff --git a/src/main/java/com/achobeta/util/ObjectUtil.java b/src/main/java/com/achobeta/util/ObjectUtil.java
index 295575d8..f87db997 100644
--- a/src/main/java/com/achobeta/util/ObjectUtil.java
+++ b/src/main/java/com/achobeta/util/ObjectUtil.java
@@ -88,4 +88,8 @@ public static void forEach(C object, Class fieldClazz, Consumer con
.forEach(consumer);
}
+ public static Stream distinctNonNullStream(Collection collection) {
+ return stream(collection).distinct().filter(Objects::nonNull);
+ }
+
}
diff --git a/src/main/resources/mapper/evaluate/ext/InterviewCommentExtMapper.xml b/src/main/resources/mapper/evaluate/ext/InterviewCommentExtMapper.xml
index e72295ae..696c6ce9 100644
--- a/src/main/resources/mapper/evaluate/ext/InterviewCommentExtMapper.xml
+++ b/src/main/resources/mapper/evaluate/ext/InterviewCommentExtMapper.xml
@@ -25,12 +25,12 @@
select
c.id, c.content, c.create_time, c.update_time,
m.id m_id, m.username m_username, m.nickname m_nickname,m.email m_email,
- m.phone_number m_phone_number, m.avatar m_acvtar
+ m.phone_number m_phone_number, m.avatar m_avatar
from interview i
left join interview_comment c on c.interview_id = i.id and c.is_deleted = 0 and i.is_deleted = 0
left join user m on m.id = c.manager_id and m.is_deleted = 0 and c.is_deleted = 0
where i.id = #{interviewId,jdbcType=BIGINT} and c.id is not null and i.is_deleted = 0
- order by c.create_time
+ order by c.create_time asc
diff --git a/src/main/resources/mapper/evaluate/ext/InterviewQuestionScoreExtMapper.xml b/src/main/resources/mapper/evaluate/ext/InterviewQuestionScoreExtMapper.xml
index 2aacc018..afb0e0c5 100644
--- a/src/main/resources/mapper/evaluate/ext/InterviewQuestionScoreExtMapper.xml
+++ b/src/main/resources/mapper/evaluate/ext/InterviewQuestionScoreExtMapper.xml
@@ -14,14 +14,18 @@
select
q.id, q.title, q.standard, q.create_time, q.update_time, avg(s.score) average
from question q
- left join interview_question_score s on q.id = s.question_id and s.is_deleted = 0 and q.is_deleted = 0 and s.score != -1
- where
- q.is_deleted = 0 and q.id
-
- #{questionId,jdbcType=BIGINT}
-
+ left join interview_question_score s on q.id = s.question_id and s.is_deleted = 0 and q.is_deleted = 0 and s.score >= 0
+ left join interview i on i.id = s.interview_id and s.is_deleted = 0 and i.is_deleted = 0
+
+ q.id is not null and q.is_deleted = 0 and i.id is not null
+
+
+ #{questionId,jdbcType=BIGINT}
+
+
+
group by q.id
- order by q.id
+ order by q.create_time
diff --git a/src/main/resources/mapper/evaluate/ext/InterviewSummaryExtMapper.xml b/src/main/resources/mapper/evaluate/ext/InterviewSummaryExtMapper.xml
index cb2106dc..5158bc45 100644
--- a/src/main/resources/mapper/evaluate/ext/InterviewSummaryExtMapper.xml
+++ b/src/main/resources/mapper/evaluate/ext/InterviewSummaryExtMapper.xml
@@ -5,18 +5,18 @@
-
-
+
+
diff --git a/src/main/resources/mapper/feedback/UserFeedbackMapper.xml b/src/main/resources/mapper/feedback/UserFeedbackMapper.xml
index bd83f350..2f580a4e 100644
--- a/src/main/resources/mapper/feedback/UserFeedbackMapper.xml
+++ b/src/main/resources/mapper/feedback/UserFeedbackMapper.xml
@@ -9,18 +9,19 @@
-
+
-
+
+
id,user_id,batch_id,
- message_id,title,content,
+ message_id,tittle,content,
attchment,is_handle,version,
is_deleted,create_time,update_time
diff --git a/src/main/resources/mapper/interview/ext/InterviewExtMapper.xml b/src/main/resources/mapper/interview/ext/InterviewExtMapper.xml
index da48a2f1..afe8fc3a 100644
--- a/src/main/resources/mapper/interview/ext/InterviewExtMapper.xml
+++ b/src/main/resources/mapper/interview/ext/InterviewExtMapper.xml
@@ -17,14 +17,12 @@
-
-
diff --git a/src/main/resources/mapper/message/MessageMapper.xml b/src/main/resources/mapper/message/MessageMapper.xml
index 2977949a..efc5abeb 100644
--- a/src/main/resources/mapper/message/MessageMapper.xml
+++ b/src/main/resources/mapper/message/MessageMapper.xml
@@ -12,6 +12,7 @@
+
diff --git a/src/main/resources/mapper/message/MessageTemplateMapper.xml b/src/main/resources/mapper/message/MessageTemplateMapper.xml
index e11c0190..6c7daaf8 100644
--- a/src/main/resources/mapper/message/MessageTemplateMapper.xml
+++ b/src/main/resources/mapper/message/MessageTemplateMapper.xml
@@ -9,6 +9,7 @@
+
diff --git a/src/main/resources/mapper/paper/ext/PaperQuestionLinkExtMapper.xml b/src/main/resources/mapper/paper/ext/PaperQuestionLinkExtMapper.xml
index 0d43205f..d359fa5e 100644
--- a/src/main/resources/mapper/paper/ext/PaperQuestionLinkExtMapper.xml
+++ b/src/main/resources/mapper/paper/ext/PaperQuestionLinkExtMapper.xml
@@ -6,11 +6,12 @@
select
- q.id, q.title, q.standard, q.create_time, q.update_time
+ q.id, q.title, q.standard, q.create_time, q.update_time, pq.create_time pq_create_time
from question_paper p
left join paper_question_link pq on p.id = pq.paper_id and p.is_deleted = 0 and pq.is_deleted = 0
left join question q on q.id = pq.question_id and q.is_deleted = 0 and pq.is_deleted = 0
where p.id = #{paperId,jdbcType=BIGINT} and q.id is not null and p.is_deleted = 0
+ order by pq_create_time asc
diff --git a/src/main/resources/mapper/paper/ext/QuestionPaperExtMapper.xml b/src/main/resources/mapper/paper/ext/QuestionPaperExtMapper.xml
index 612ac9c7..6c027d12 100644
--- a/src/main/resources/mapper/paper/ext/QuestionPaperExtMapper.xml
+++ b/src/main/resources/mapper/paper/ext/QuestionPaperExtMapper.xml
@@ -16,19 +16,38 @@
resultMap="com.achobeta.domain.paper.model.dao.mapper.QuestionPaperMapper.BaseResultMap">
select
-- 试卷与试卷库多对多,在本条 sql 容易出现重复行
- distinct p.id, p.title, p.description, p.create_time, p.update_time
+ distinct p.id, p.title, p.description, p.create_time, p.update_time, lp.create_time lp_create_time
from question_paper_library l
left join library_paper_link lp on l.id = lp.lib_id and l.is_deleted = 0 and lp.is_deleted = 0
left join question_paper p on p.id = lp.paper_id and p.is_deleted = 0 and lp.is_deleted = 0
p.id is not null and l.is_deleted = 0
- and l.id
-
+
#{libId,jdbcType=BIGINT}
+ order by lp_create_time asc
+
+
+
+ select
+ -- 试卷与试卷库多对多,在本条 sql 容易出现重复行
+ distinct p.id, p.title, p.description, p.create_time, p.update_time, lp.create_time lp_create_time
+ from question_paper_library l
+ left join library_paper_link lp on l.id = lp.lib_id and l.is_deleted = 0 and lp.is_deleted = 0
+ left join question_paper p on p.id = lp.paper_id and p.is_deleted = 0 and lp.is_deleted = 0
+
+ p.id is not null and l.is_deleted = 0
+
+
+ #{libId,jdbcType=BIGINT}
+
+
+
+ order by lp_create_time asc
diff --git a/src/main/resources/mapper/paper/ext/QuestionPaperLibraryExtMapper.xml b/src/main/resources/mapper/paper/ext/QuestionPaperLibraryExtMapper.xml
index 1edfb210..9aed00d7 100644
--- a/src/main/resources/mapper/paper/ext/QuestionPaperLibraryExtMapper.xml
+++ b/src/main/resources/mapper/paper/ext/QuestionPaperLibraryExtMapper.xml
@@ -19,10 +19,11 @@
select
p.id, p.title, p.description, p.create_time, p.update_time,
- l.id l_id, l.lib_type l_lib_type, l.create_time l_create_time
+ l.id l_id, l.lib_type l_lib_type, l.create_time l_create_time, lp.create_time lp_create_time
from question_paper p
left join library_paper_link lp on p.id = lp.paper_id and p.is_deleted = 0 and lp.is_deleted = 0
left join question_paper_library l on l.id = lp.lib_id and l.is_deleted = 0 and lp.is_deleted = 0
where p.id = #{paperId,jdbcType=BIGINT} and p.is_deleted = 0
+ order by lp_create_time asc
diff --git a/src/main/resources/mapper/question/ext/QuestionExtMapper.xml b/src/main/resources/mapper/question/ext/QuestionExtMapper.xml
index 4b3145de..293cbc0b 100644
--- a/src/main/resources/mapper/question/ext/QuestionExtMapper.xml
+++ b/src/main/resources/mapper/question/ext/QuestionExtMapper.xml
@@ -16,18 +16,37 @@
resultMap="com.achobeta.domain.question.model.dao.mapper.QuestionMapper.BaseResultMap">
select
-- 问题与题库多对多,在本条 sql 容易出现重复行
- distinct q.id, q.title, q.standard, q.create_time, q.update_time
+ distinct q.id, q.title, q.standard, q.create_time, q.update_time, lq.create_time lq_create_time
from question_library l
left join library_question_link lq on l.id = lq.lib_id and l.is_deleted = 0 and lq.is_deleted = 0
left join question q on q.id = lq.question_id and q.is_deleted = 0 and lq.is_deleted = 0
q.id is not null and l.is_deleted = 0
- and l.id
-
+
#{libId,jdbcType=BIGINT}
+ order by lq_create_time asc
+
+
+
+ select
+ -- 问题与题库多对多,在本条 sql 容易出现重复行
+ distinct q.id, q.title, q.standard, q.create_time, q.update_time, lq.create_time lq_create_time
+ from question_library l
+ left join library_question_link lq on l.id = lq.lib_id and l.is_deleted = 0 and lq.is_deleted = 0
+ left join question q on q.id = lq.question_id and q.is_deleted = 0 and lq.is_deleted = 0
+
+ q.id is not null and l.is_deleted = 0
+
+
+ #{libId,jdbcType=BIGINT}
+
+
+
+ order by lq_create_time asc
diff --git a/src/main/resources/mapper/question/ext/QuestionLibararyExtMapper.xml b/src/main/resources/mapper/question/ext/QuestionLibararyExtMapper.xml
index 8101f804..a3e3bb24 100644
--- a/src/main/resources/mapper/question/ext/QuestionLibararyExtMapper.xml
+++ b/src/main/resources/mapper/question/ext/QuestionLibararyExtMapper.xml
@@ -19,11 +19,12 @@
select
q.id, q.title, q.standard, q.create_time, q.update_time,
- l.id l_id, l.lib_type l_lib_type, l.create_time l_create_time
+ l.id l_id, l.lib_type l_lib_type, l.create_time l_create_time, lq.create_time lq_create_time
from question q
left join library_question_link lq on q.id = lq.question_id and q.is_deleted = 0 and lq.is_deleted = 0
left join question_library l on l.id = lq.lib_id and l.is_deleted = 0 and lq.is_deleted = 0
where q.id = #{questionId,jdbcType=BIGINT} and q.is_deleted = 0
+ order by lq_create_time asc
diff --git a/src/main/resources/mapper/recruit/ext/ActivityParticipationExtMapper.xml b/src/main/resources/mapper/recruit/ext/ActivityParticipationExtMapper.xml
index 8323ec75..d167e22c 100644
--- a/src/main/resources/mapper/recruit/ext/ActivityParticipationExtMapper.xml
+++ b/src/main/resources/mapper/recruit/ext/ActivityParticipationExtMapper.xml
@@ -29,12 +29,13 @@
select
- q.id, q.title, pq.answer
+ q.id, q.title, pq.answer, pq.create_time pq_create_time
from
activity_participation ap
left join participation_question_link pq on ap.id = pq.participation_id and ap.is_deleted = 0 and pq.is_deleted = 0
left join question q on pq.question_id = q.id and pq.is_deleted = 0 and q.is_deleted = 0
where ap.id = #{participationId,jdbcType=BIGINT} and q.id is not null and ap.is_deleted = 0
+ order by pq_create_time
@@ -55,27 +56,36 @@
activity_participation ap
left join participation_period_link pp on ap.id = pp.participation_id and ap.is_deleted = 0 and pp.is_deleted = 0
left join time_period t on pp.period_id = t.id and pp.is_deleted = 0 and t.is_deleted = 0
- where ap.is_deleted = 0 and ap.id
-
- #{participationId,jdbcType=BIGINT}
-
+
+ ap.id is not null and ap.is_deleted = 0
+
+
+ #{participationId,jdbcType=BIGINT}
+
+
+
order by t.start_time asc, t.end_time asc
select
- ap.id, q.id q_id, q.title q_title, pq.answer q_answer,
+ ap.id, q.id q_id, q.title q_title, pq.answer q_answer, pq.create_time pq_create_time,
from
- activity_participation ap
+ activity_participation ap
left join recruitment_activity a on a.id = ap.act_id and a.is_deleted = 0 and ap.is_deleted = 0
left join recruitment_batch b on b.id = a.batch_id and b.is_deleted = 0 and a.is_deleted = 0
left join stu_resume r on r.batch_id = b.id and r.user_id = ap.stu_id and b.is_deleted = 0 and r.is_deleted = 0
left join participation_question_link pq on ap.id = pq.participation_id and ap.is_deleted = 0 and pq.is_deleted = 0
left join question q on pq.question_id = q.id and pq.is_deleted = 0 and q.is_deleted = 0
- where ap.is_deleted = 0 and ap.id
-
- #{participationId,jdbcType=BIGINT}
-
+
+ ap.id is not null and ap.is_deleted = 0
+
+
+ #{participationId,jdbcType=BIGINT}
+
+
+
+ order by pq_create_time asc
diff --git a/src/main/resources/mapper/recruit/ext/RecruitmentBatchExtMapper.xml b/src/main/resources/mapper/recruit/ext/RecruitmentBatchExtMapper.xml
index 7ccb9f79..e005fa32 100644
--- a/src/main/resources/mapper/recruit/ext/RecruitmentBatchExtMapper.xml
+++ b/src/main/resources/mapper/recruit/ext/RecruitmentBatchExtMapper.xml
@@ -6,10 +6,11 @@
select
- s.id, s.user_id, s.student_id, s.name, u.username, s.email, s.gender, s.grade, s.major, s.class, s.status
+ s.id, s.user_id, s.student_id, s.name, u.username, s.email, s.gender, s.grade, s.major, s.class, s.status, s.create_time
from recruitment_batch rb
left join stu_resume s on s.batch_id = rb.id and s.is_deleted = 0 and rb.is_deleted = 0
left join user u on s.user_id = u.id and s.is_deleted = 0 and u.is_deleted = 0
where rb.id = #{batchId,jdbcType=BIGINT} and s.id is not null and rb.is_deleted = 0
+ order by s.create_time asc
diff --git a/src/main/resources/mapper/schedule/ext/InterviewScheduleExtMapper.xml b/src/main/resources/mapper/schedule/ext/InterviewScheduleExtMapper.xml
index f23092fe..c319b840 100644
--- a/src/main/resources/mapper/schedule/ext/InterviewScheduleExtMapper.xml
+++ b/src/main/resources/mapper/schedule/ext/InterviewScheduleExtMapper.xml
@@ -4,15 +4,6 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-
-
-
-
-
-
-
-
-
@@ -25,7 +16,9 @@
-
+
+
+
@@ -34,19 +27,21 @@
-
+
select
-- 面试预约与面试官多对多,在本条 sql 容易出现重复行
distinct s.id, s.participation_id, s.start_time, s.end_time,
+ i.id i_id, i.title i_title, i.status i_status,
from user m
- left join interviewer i on m.id = i.manager_id and m.is_deleted = 0 and i.is_deleted = 0
- left join interview_schedule s on i.schedule_id = s.id and i.is_deleted = 0 and s.is_deleted = 0
- left join activity_participation p on p.id = s.participation_id and p.is_deleted = 0 and s.is_deleted = 0
- left join user stu on p.stu_id = stu.id and p.is_deleted = 0 and stu.is_deleted = 0
- left join recruitment_activity a on p.act_id = a.id and p.is_deleted = 0 and a.is_deleted = 0
- left join recruitment_batch b on a.batch_id = b.id and a.is_deleted = 0 and b.is_deleted = 0
- left join stu_resume r on r.batch_id = b.id and r.user_id = stu.id and r.is_deleted = 0 and b.is_deleted = 0 and stu.is_deleted = 0
+ left join interviewer ir on m.id = ir.manager_id and m.is_deleted = 0 and ir.is_deleted = 0
+ left join interview_schedule s on ir.schedule_id = s.id and ir.is_deleted = 0 and s.is_deleted = 0
+ left join activity_participation p on p.id = s.participation_id and p.is_deleted = 0 and s.is_deleted = 0
+ left join user stu on p.stu_id = stu.id and p.is_deleted = 0 and stu.is_deleted = 0
+ left join recruitment_activity a on p.act_id = a.id and p.is_deleted = 0 and a.is_deleted = 0
+ left join recruitment_batch b on a.batch_id = b.id and a.is_deleted = 0 and b.is_deleted = 0
+ left join stu_resume r on r.batch_id = b.id and r.user_id = stu.id and r.is_deleted = 0 and b.is_deleted = 0 and stu.is_deleted = 0
+ left join interview i on i.schedule_id = s.id and i.is_deleted = 0 and s.is_deleted = 0
s.id is not null and m.is_deleted = 0
@@ -62,7 +57,7 @@
order by s.start_time asc, s.end_time asc
-
+
select
p.id, s.id s_id, s.participation_id s_participation_id, s.start_time s_start_time, s.end_time s_end_time,
@@ -72,7 +67,15 @@
left join recruitment_batch b on a.batch_id = b.id and a.is_deleted = 0 and b.is_deleted = 0
left join stu_resume r on r.batch_id = b.id and r.user_id = stu.id and r.is_deleted = 0 and b.is_deleted = 0 and stu.is_deleted = 0
left join interview_schedule s on s.participation_id = p.id and s.is_deleted = 0 and p.is_deleted = 0
- where a.id = #{actId,jdbcType=BIGINT} and r.id is not null and p.is_deleted = 0
+
+ a.id = #{condition.actId,jdbcType=BIGINT} and r.id is not null and p.is_deleted = 0
+ -- and r.status 放在外面,foreach 内部为空导致没有 in,可能会因为 r.status 为 0 而没有查询到一些行
+
+
+ #{status,jdbcType=INTEGER}
+
+
+
order by s.start_time asc, s.end_time asc
@@ -93,7 +96,7 @@
select
s.id, s.participation_id, s.start_time, s.end_time,
- m.id m_id, m.username m_username, m.nickname m_nickname,m.email m_email,
+ m.id m_id, m.username m_username, m.nickname m_nickname, m.email m_email,
m.phone_number m_phone_number, m.avatar m_acvtar,
from interview_schedule s
diff --git a/src/main/resources/mapper/schedule/ext/InterviewerExtMapper.xml b/src/main/resources/mapper/schedule/ext/InterviewerExtMapper.xml
new file mode 100644
index 00000000..e5bd102a
--- /dev/null
+++ b/src/main/resources/mapper/schedule/ext/InterviewerExtMapper.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select
+ s.id, s.participation_id, s.start_time, s.end_time,
+ m.id m_id, m.username m_username, m.nickname m_nickname, m.email m_email,
+ m.phone_number m_phone_number, m.avatar m_acvtar
+ from interview_schedule s
+ left join interviewer i on s.id = i.schedule_id and s.is_deleted = 0 and i.is_deleted = 0
+ left join user m on m.id = i.manager_id and m.is_deleted = 0 and i.is_deleted = 0
+
+ s.id is not null and s.is_deleted = 0 and m.id is not null
+
+
+ #{scheduleId,jdbcType=BIGINT}
+
+
+
+ order by s.start_time asc, s.end_time asc
+
+
+
diff --git a/src/main/resources/templates/interview-experience-model.html b/src/main/resources/templates/interview-experience-model.html
index 5d4913c9..20480f96 100644
--- a/src/main/resources/templates/interview-experience-model.html
+++ b/src/main/resources/templates/interview-experience-model.html
@@ -30,8 +30,8 @@
-
-
+
+
得分(0-10):
问题超纲
@@ -39,8 +39,6 @@
- 历史平均分:
-
标准答案: