12312
This commit is contained in:
commit
239fa7b92a
249 files changed
+43765
-999
No files matched your search
@@ -407,6 +407,12 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 社团管理模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-stgl</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -135,6 +135,13 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 社团管理模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-stgl</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- 添加批次ID字段
|
||||
ALTER TABLE xljk_consultation_schedule ADD COLUMN batch_id VARCHAR(50) DEFAULT NULL COMMENT '批次ID,用于标识同一批次创建的预约时段';
|
||||
@@ -300,3 +300,44 @@ justauth:
|
||||
client-id: 10**********6
|
||||
client-secret: 1f7d08**********5b7**********29e
|
||||
redirect-uri: ${justauth.address}/social-callback?source=gitea
|
||||
|
||||
system:
|
||||
file-cache:
|
||||
# 是否启用文件缓存
|
||||
enabled: true
|
||||
|
||||
# 最大缓存文件数量
|
||||
max-cache-size: 100
|
||||
|
||||
# 最大缓存大小(字节)- 500MB
|
||||
max-cache-size-bytes: 524288000
|
||||
|
||||
# 缓存过期时间(毫秒)- 30分钟
|
||||
expire-time-ms: 1800000
|
||||
|
||||
# 最大缓存单个文件大小(字节)- 50MB
|
||||
max-single-file-size: 52428800
|
||||
|
||||
# LRU淘汰比例(百分比)
|
||||
evict-ratio: 20
|
||||
|
||||
# 是否启用缓存统计
|
||||
enable-stats: true
|
||||
|
||||
# 缓存清理间隔(毫秒)- 5分钟
|
||||
cleanup-interval-ms: 300000
|
||||
# 配置说明:
|
||||
# 1. enabled: 控制是否启用文件缓存功能
|
||||
# 2. max-cache-size: 缓存的最大文件数量
|
||||
# 3. max-cache-size-bytes: 缓存的最大总大小(字节)
|
||||
# 4. expire-time-ms: 缓存条目的过期时间(毫秒)
|
||||
# 5. max-single-file-size: 单个文件的最大缓存大小(字节)
|
||||
# 6. evict-ratio: LRU淘汰时移除的条目比例(百分比)
|
||||
# 7. enable-stats: 是否启用缓存统计功能
|
||||
# 8. cleanup-interval-ms: 自动清理过期条目的间隔(毫秒)
|
||||
|
||||
# 性能优化建议:
|
||||
# - 对于内存充足的环境,可以适当增加 max-cache-size-bytes
|
||||
# - 对于频繁访问的小文件,可以增加 max-cache-size
|
||||
# - 对于大文件较多的环境,可以调整 max-single-file-size
|
||||
# - 对于访问频率较低的环境,可以适当减少 expire-time-ms
|
||||
@@ -0,0 +1,43 @@
|
||||
# 🚀 文件缓存配置示例
|
||||
# 将此配置添加到 application.yml 或 application-dev.yml 中
|
||||
|
||||
system:
|
||||
file-cache:
|
||||
# 是否启用文件缓存
|
||||
enabled: true
|
||||
|
||||
# 最大缓存文件数量
|
||||
max-cache-size: 100
|
||||
|
||||
# 最大缓存大小(字节)- 500MB
|
||||
max-cache-size-bytes: 524288000
|
||||
|
||||
# 缓存过期时间(毫秒)- 30分钟
|
||||
expire-time-ms: 1800000
|
||||
|
||||
# 最大缓存单个文件大小(字节)- 50MB
|
||||
max-single-file-size: 52428800
|
||||
|
||||
# LRU淘汰比例(百分比)
|
||||
evict-ratio: 20
|
||||
|
||||
# 是否启用缓存统计
|
||||
enable-stats: true
|
||||
|
||||
# 缓存清理间隔(毫秒)- 5分钟
|
||||
cleanup-interval-ms: 300000
|
||||
# 配置说明:
|
||||
# 1. enabled: 控制是否启用文件缓存功能
|
||||
# 2. max-cache-size: 缓存的最大文件数量
|
||||
# 3. max-cache-size-bytes: 缓存的最大总大小(字节)
|
||||
# 4. expire-time-ms: 缓存条目的过期时间(毫秒)
|
||||
# 5. max-single-file-size: 单个文件的最大缓存大小(字节)
|
||||
# 6. evict-ratio: LRU淘汰时移除的条目比例(百分比)
|
||||
# 7. enable-stats: 是否启用缓存统计功能
|
||||
# 8. cleanup-interval-ms: 自动清理过期条目的间隔(毫秒)
|
||||
|
||||
# 性能优化建议:
|
||||
# - 对于内存充足的环境,可以适当增加 max-cache-size-bytes
|
||||
# - 对于频繁访问的小文件,可以增加 max-cache-size
|
||||
# - 对于大文件较多的环境,可以调整 max-single-file-size
|
||||
# - 对于访问频率较低的环境,可以适当减少 expire-time-ms
|
||||
@@ -52,9 +52,9 @@ spring:
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
||||
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
||||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||
url: jdbc:mysql://47.99.164.66:3306/hzdyjs_xg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||
username: root
|
||||
password: root
|
||||
password: 'hn02le.34lkdLKD'
|
||||
# # 从库数据源
|
||||
# slave:
|
||||
# lazy: true
|
||||
@@ -272,3 +272,44 @@ justauth:
|
||||
client-id: 10**********6
|
||||
client-secret: 1f7d08**********5b7**********29e
|
||||
redirect-uri: ${justauth.address}/social-callback?source=gitea
|
||||
|
||||
system:
|
||||
file-cache:
|
||||
# 是否启用文件缓存
|
||||
enabled: true
|
||||
|
||||
# 最大缓存文件数量
|
||||
max-cache-size: 100
|
||||
|
||||
# 最大缓存大小(字节)- 500MB
|
||||
max-cache-size-bytes: 524288000
|
||||
|
||||
# 缓存过期时间(毫秒)- 30分钟
|
||||
expire-time-ms: 1800000
|
||||
|
||||
# 最大缓存单个文件大小(字节)- 50MB
|
||||
max-single-file-size: 52428800
|
||||
|
||||
# LRU淘汰比例(百分比)
|
||||
evict-ratio: 20
|
||||
|
||||
# 是否启用缓存统计
|
||||
enable-stats: true
|
||||
|
||||
# 缓存清理间隔(毫秒)- 5分钟
|
||||
cleanup-interval-ms: 300000
|
||||
# 配置说明:
|
||||
# 1. enabled: 控制是否启用文件缓存功能
|
||||
# 2. max-cache-size: 缓存的最大文件数量
|
||||
# 3. max-cache-size-bytes: 缓存的最大总大小(字节)
|
||||
# 4. expire-time-ms: 缓存条目的过期时间(毫秒)
|
||||
# 5. max-single-file-size: 单个文件的最大缓存大小(字节)
|
||||
# 6. evict-ratio: LRU淘汰时移除的条目比例(百分比)
|
||||
# 7. enable-stats: 是否启用缓存统计功能
|
||||
# 8. cleanup-interval-ms: 自动清理过期条目的间隔(毫秒)
|
||||
|
||||
# 性能优化建议:
|
||||
# - 对于内存充足的环境,可以适当增加 max-cache-size-bytes
|
||||
# - 对于频繁访问的小文件,可以增加 max-cache-size
|
||||
# - 对于大文件较多的环境,可以调整 max-single-file-size
|
||||
# - 对于访问频率较低的环境,可以适当减少 expire-time-ms
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package org.dromara.common.excel.convert;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.idev.excel.converters.Converter;
|
||||
import cn.idev.excel.enums.CellDataTypeEnum;
|
||||
import cn.idev.excel.metadata.GlobalConfiguration;
|
||||
import cn.idev.excel.metadata.data.ReadCellData;
|
||||
import cn.idev.excel.metadata.data.WriteCellData;
|
||||
import cn.idev.excel.metadata.property.ExcelContentProperty;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Excel日期转换器
|
||||
* 日期格式转换为yyyy-MM-dd格式
|
||||
*
|
||||
* @author Cursor AI
|
||||
*/
|
||||
@Slf4j
|
||||
public class ExcelDateConverter implements Converter<Date> {
|
||||
|
||||
@Override
|
||||
public Class<Date> supportJavaTypeKey() {
|
||||
return Date.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CellDataTypeEnum supportExcelTypeKey() {
|
||||
return CellDataTypeEnum.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
|
||||
if (ObjectUtil.isNull(cellData.getData())) {
|
||||
return null;
|
||||
}
|
||||
return DateUtil.parse(cellData.getStringValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WriteCellData<String> convertToExcelData(Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
|
||||
if (ObjectUtil.isNull(value)) {
|
||||
return new WriteCellData<>("");
|
||||
}
|
||||
return new WriteCellData<>(DateUtil.format(value, "yyyy-MM-dd"));
|
||||
}
|
||||
}
|
||||
+87
-74
@@ -79,35 +79,45 @@ public class OssClient {
|
||||
try {
|
||||
// 创建 AWS 认证信息
|
||||
StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
|
||||
AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
|
||||
AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
|
||||
|
||||
// MinIO 使用 HTTPS 限制使用域名访问,站点填域名。需要启用路径样式访问
|
||||
boolean isStyle = !StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE);
|
||||
|
||||
// 创建AWS基于 Netty 的 S3 客户端
|
||||
this.client = S3AsyncClient.builder()
|
||||
.credentialsProvider(credentialsProvider)
|
||||
.endpointOverride(URI.create(getEndpoint()))
|
||||
.region(of())
|
||||
.forcePathStyle(isStyle)
|
||||
.httpClient(NettyNioAsyncHttpClient.builder()
|
||||
.connectionTimeout(Duration.ofSeconds(60)).build())
|
||||
.build();
|
||||
.credentialsProvider(credentialsProvider)
|
||||
.endpointOverride(URI.create(getEndpoint()))
|
||||
.region(of())
|
||||
.forcePathStyle(isStyle)
|
||||
.httpClient(NettyNioAsyncHttpClient.builder()
|
||||
// 🚀 优化:连接超时时间(60秒)
|
||||
.connectionTimeout(Duration.ofSeconds(60))
|
||||
// 🚀 优化:读取超时时间(300秒,适合大文件下载)
|
||||
.readTimeout(Duration.ofSeconds(300))
|
||||
// 🚀 优化:写入超时时间(300秒,适合大文件上传)
|
||||
.writeTimeout(Duration.ofSeconds(300))
|
||||
.build())
|
||||
.build();
|
||||
|
||||
//AWS基于 CRT 的 S3 AsyncClient 实例用作 S3 传输管理器的底层客户端
|
||||
this.transferManager = S3TransferManager.builder().s3Client(this.client).build();
|
||||
// 🚀 优化:S3传输管理器配置
|
||||
this.transferManager = S3TransferManager.builder()
|
||||
.s3Client(this.client)
|
||||
.build();
|
||||
|
||||
// 创建 S3 配置对象
|
||||
S3Configuration config = S3Configuration.builder().chunkedEncodingEnabled(false)
|
||||
.pathStyleAccessEnabled(isStyle).build();
|
||||
S3Configuration config = S3Configuration.builder()
|
||||
.chunkedEncodingEnabled(false)
|
||||
.pathStyleAccessEnabled(isStyle)
|
||||
.build();
|
||||
|
||||
// 创建 预签名 URL 的生成器 实例,用于生成 S3 预签名 URL
|
||||
this.presigner = S3Presigner.builder()
|
||||
.region(of())
|
||||
.credentialsProvider(credentialsProvider)
|
||||
.endpointOverride(URI.create(getDomain()))
|
||||
.serviceConfiguration(config)
|
||||
.build();
|
||||
.region(of())
|
||||
.credentialsProvider(credentialsProvider)
|
||||
.endpointOverride(URI.create(getDomain()))
|
||||
.serviceConfiguration(config)
|
||||
.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
if (e instanceof OssException) {
|
||||
@@ -131,17 +141,17 @@ public class OssClient {
|
||||
try {
|
||||
// 构建上传请求对象
|
||||
FileUpload fileUpload = transferManager.uploadFile(
|
||||
x -> x.putObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
|
||||
.contentType(contentType)
|
||||
// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,
|
||||
// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)
|
||||
//.acl(getAccessPolicy().getObjectCannedACL())
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
.source(filePath).build());
|
||||
x -> x.putObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
|
||||
.contentType(contentType)
|
||||
// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,
|
||||
// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)
|
||||
// .acl(getAccessPolicy().getObjectCannedACL())
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
.source(filePath).build());
|
||||
|
||||
// 等待上传完成并获取上传结果
|
||||
CompletedFileUpload uploadResult = fileUpload.completionFuture().join();
|
||||
@@ -176,22 +186,22 @@ public class OssClient {
|
||||
try {
|
||||
// 创建异步请求体(length如果为空会报错)
|
||||
BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
|
||||
.contentLength(length)
|
||||
.subscribeTimeout(Duration.ofSeconds(30))
|
||||
.build();
|
||||
.contentLength(length)
|
||||
.subscribeTimeout(Duration.ofSeconds(30))
|
||||
.build();
|
||||
|
||||
// 使用 transferManager 进行上传
|
||||
Upload upload = transferManager.upload(
|
||||
x -> x.requestBody(body)
|
||||
.putObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.contentType(contentType)
|
||||
// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,
|
||||
// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)
|
||||
//.acl(getAccessPolicy().getObjectCannedACL())
|
||||
.build())
|
||||
.build());
|
||||
x -> x.requestBody(body)
|
||||
.putObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.contentType(contentType)
|
||||
// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,
|
||||
// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)
|
||||
// .acl(getAccessPolicy().getObjectCannedACL())
|
||||
.build())
|
||||
.build());
|
||||
|
||||
// 将输入流写入请求体
|
||||
body.writeInputStream(inputStream);
|
||||
@@ -219,13 +229,13 @@ public class OssClient {
|
||||
Path tempFilePath = FileUtils.createTempFile().toPath();
|
||||
// 使用 S3TransferManager 下载文件
|
||||
FileDownload downloadFile = transferManager.downloadFile(
|
||||
x -> x.getObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(removeBaseUrl(path))
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
.destination(tempFilePath)
|
||||
.build());
|
||||
x -> x.getObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(removeBaseUrl(path))
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
.destination(tempFilePath)
|
||||
.build());
|
||||
// 等待文件下载操作完成
|
||||
downloadFile.completionFuture().join();
|
||||
return tempFilePath;
|
||||
@@ -234,8 +244,8 @@ public class OssClient {
|
||||
/**
|
||||
* 下载文件从 Amazon S3 到 输出流
|
||||
*
|
||||
* @param key 文件在 Amazon S3 中的对象键
|
||||
* @param out 输出流
|
||||
* @param key 文件在 Amazon S3 中的对象键
|
||||
* @param out 输出流
|
||||
* @param consumer 自定义处理逻辑
|
||||
* @return 输出流中写入的字节数(长度)
|
||||
* @throws OssException 如果下载失败,抛出自定义异常
|
||||
@@ -244,18 +254,19 @@ public class OssClient {
|
||||
try {
|
||||
// 构建下载请求
|
||||
DownloadRequest<ResponseInputStream<GetObjectResponse>> downloadRequest = DownloadRequest.builder()
|
||||
// 文件对象
|
||||
.getObjectRequest(y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
// 使用订阅转换器
|
||||
.responseTransformer(AsyncResponseTransformer.toBlockingInputStream())
|
||||
.build();
|
||||
// 文件对象
|
||||
.getObjectRequest(y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
// 使用订阅转换器
|
||||
.responseTransformer(AsyncResponseTransformer.toBlockingInputStream())
|
||||
.build();
|
||||
// 使用 S3TransferManager 下载文件
|
||||
Download<ResponseInputStream<GetObjectResponse>> responseFuture = transferManager.download(downloadRequest);
|
||||
// 输出到流中
|
||||
try (ResponseInputStream<GetObjectResponse> responseStream = responseFuture.completionFuture().join().result()) { // auto-closeable stream
|
||||
try (ResponseInputStream<GetObjectResponse> responseStream = responseFuture.completionFuture().join()
|
||||
.result()) { // auto-closeable stream
|
||||
if (consumer != null) {
|
||||
consumer.accept(responseStream.response().contentLength());
|
||||
}
|
||||
@@ -274,9 +285,9 @@ public class OssClient {
|
||||
public void delete(String path) {
|
||||
try {
|
||||
client.deleteObject(
|
||||
x -> x.bucket(properties.getBucketName())
|
||||
.key(removeBaseUrl(path))
|
||||
.build());
|
||||
x -> x.bucket(properties.getBucketName())
|
||||
.key(removeBaseUrl(path))
|
||||
.build());
|
||||
} catch (Exception e) {
|
||||
throw new OssException("删除文件失败,请检查配置信息:[" + e.getMessage() + "]");
|
||||
}
|
||||
@@ -292,12 +303,12 @@ public class OssClient {
|
||||
// 使用 AWS S3 预签名 URL 的生成器 获取对象的预签名 URL
|
||||
URL url = presigner.presignGetObject(
|
||||
x -> x.signatureDuration(expiredTime)
|
||||
.getObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(objectKey)
|
||||
.build())
|
||||
.build())
|
||||
.url();
|
||||
.getObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(objectKey)
|
||||
.build())
|
||||
.build())
|
||||
.url();
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
@@ -310,7 +321,8 @@ public class OssClient {
|
||||
* @throws OssException 如果上传失败,抛出自定义异常
|
||||
*/
|
||||
public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) {
|
||||
return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix), Long.valueOf(data.length), contentType);
|
||||
return upload(new ByteArrayInputStream(data), getPath(properties.getPrefix(), suffix),
|
||||
Long.valueOf(data.length), contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,7 +412,7 @@ public class OssClient {
|
||||
* @return 对应的 AWS 区域对象,或者默认的广泛支持的区域(us-east-1)
|
||||
*/
|
||||
public Region of() {
|
||||
//AWS 区域字符串
|
||||
// AWS 区域字符串
|
||||
String region = properties.getRegion();
|
||||
// 如果 region 参数非空,使用 Region.of 方法创建对应的 AWS 区域对象,否则返回默认区域
|
||||
return StringUtils.isNotEmpty(region) ? Region.of(region) : Region.US_EAST_1;
|
||||
@@ -422,8 +434,9 @@ public class OssClient {
|
||||
// MinIO 单独处理
|
||||
if (StringUtils.isNotEmpty(domain)) {
|
||||
// 如果 domain 以 "https://" 或 "http://" 开头
|
||||
return (domain.startsWith(Constants.HTTPS) || domain.startsWith(Constants.HTTP)) ?
|
||||
domain + StringUtils.SLASH + properties.getBucketName() : header + domain + StringUtils.SLASH + properties.getBucketName();
|
||||
return (domain.startsWith(Constants.HTTPS) || domain.startsWith(Constants.HTTP))
|
||||
? domain + StringUtils.SLASH + properties.getBucketName()
|
||||
: header + domain + StringUtils.SLASH + properties.getBucketName();
|
||||
}
|
||||
return header + endpoint + StringUtils.SLASH + properties.getBucketName();
|
||||
}
|
||||
@@ -441,8 +454,8 @@ public class OssClient {
|
||||
// 生成日期路径
|
||||
String datePath = DateUtils.datePath();
|
||||
// 拼接路径
|
||||
String path = StringUtils.isNotEmpty(prefix) ?
|
||||
prefix + StringUtils.SLASH + datePath + StringUtils.SLASH + uuid : datePath + StringUtils.SLASH + uuid;
|
||||
String path = StringUtils.isNotEmpty(prefix) ? prefix + StringUtils.SLASH + datePath + StringUtils.SLASH + uuid
|
||||
: datePath + StringUtils.SLASH + uuid;
|
||||
return path + suffix;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<module>ruoyi-cw</module>
|
||||
<module>ruoyi-rs</module>
|
||||
<module>ruoyi-xljk</module>
|
||||
<module>ruoyi-stgl</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
|
||||
+51
-8
@@ -22,6 +22,7 @@ import org.dromara.hq.domain.vo.HqPmRepairAttachmentVo;
|
||||
import org.dromara.hq.mapper.HqPmRepairAttachmentMapper;
|
||||
import org.dromara.hq.mapper.HqPmRepairOrderMapper;
|
||||
import org.dromara.hq.service.IHqPmRepairAttachmentService;
|
||||
import org.dromara.system.service.ISysOssService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@@ -44,6 +45,7 @@ public class HqPmRepairAttachmentServiceImpl implements IHqPmRepairAttachmentSer
|
||||
|
||||
private final HqPmRepairAttachmentMapper baseMapper;
|
||||
private final HqPmRepairOrderMapper repairOrderMapper;
|
||||
private final ISysOssService sysOssService;
|
||||
|
||||
/**
|
||||
* 查询报修附件
|
||||
@@ -160,11 +162,31 @@ public class HqPmRepairAttachmentServiceImpl implements IHqPmRepairAttachmentSer
|
||||
for (HqPmRepairAttachmentVo attachment : attachments) {
|
||||
try {
|
||||
if (StringUtils.isNotBlank(attachment.getFilePath())) {
|
||||
OssFactory.instance().delete(attachment.getFilePath());
|
||||
// 从文件路径中提取ossId
|
||||
String filePath = attachment.getFilePath();
|
||||
if (filePath.contains("/resource/oss/download/")) {
|
||||
String ossIdStr = filePath.substring(filePath.lastIndexOf("/") + 1);
|
||||
try {
|
||||
Long ossId = Long.parseLong(ossIdStr);
|
||||
sysOssService.deleteWithValidByIds(List.of(ossId), true);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法从文件路径中解析ossId: {}", filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 删除缩略图
|
||||
if (StringUtils.isNotBlank(attachment.getThumbnailPath())) {
|
||||
OssFactory.instance().delete(attachment.getThumbnailPath());
|
||||
// 从缩略图路径中提取ossId
|
||||
String thumbnailPath = attachment.getThumbnailPath();
|
||||
if (thumbnailPath.contains("/resource/oss/download/")) {
|
||||
String ossIdStr = thumbnailPath.substring(thumbnailPath.lastIndexOf("/") + 1);
|
||||
try {
|
||||
Long ossId = Long.parseLong(ossIdStr);
|
||||
sysOssService.deleteWithValidByIds(List.of(ossId), true);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法从缩略图路径中解析ossId: {}", thumbnailPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("删除OSS文件失败: {}", e.getMessage());
|
||||
@@ -196,14 +218,15 @@ public class HqPmRepairAttachmentServiceImpl implements IHqPmRepairAttachmentSer
|
||||
String contentType = file.getContentType();
|
||||
long fileSize = file.getSize();
|
||||
|
||||
// 上传文件到OSS
|
||||
UploadResult uploadResult = OssFactory.instance().uploadSuffix(file.getBytes(), fileExtension, contentType);
|
||||
// 通过SysOssService上传文件,获取ossId
|
||||
var sysOssVo = sysOssService.upload(file);
|
||||
|
||||
// 构建附件信息
|
||||
HqPmRepairAttachmentBo bo = new HqPmRepairAttachmentBo();
|
||||
bo.setOrderId(orderId);
|
||||
bo.setFileName(originalFilename);
|
||||
bo.setFilePath(uploadResult.getUrl());
|
||||
// bo.setFilePath("/resource/oss/download/" + sysOssVo.getOssId());
|
||||
bo.setFilePath(sysOssVo.getOssId().toString());
|
||||
bo.setFileSize(fileSize);
|
||||
bo.setFileType(getFileType(contentType));
|
||||
bo.setFileExtension(fileExtension);
|
||||
@@ -220,7 +243,7 @@ public class HqPmRepairAttachmentServiceImpl implements IHqPmRepairAttachmentSer
|
||||
} else {
|
||||
throw new RuntimeException("保存附件信息失败");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
} catch (Exception e) {
|
||||
log.error("上传附件失败: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("上传附件失败: " + e.getMessage());
|
||||
}
|
||||
@@ -265,10 +288,30 @@ public class HqPmRepairAttachmentServiceImpl implements IHqPmRepairAttachmentSer
|
||||
// 删除OSS文件
|
||||
try {
|
||||
if (StringUtils.isNotBlank(attachment.getFilePath())) {
|
||||
OssFactory.instance().delete(attachment.getFilePath());
|
||||
// 从文件路径中提取ossId
|
||||
String filePath = attachment.getFilePath();
|
||||
if (filePath.contains("/resource/oss/download/")) {
|
||||
String ossIdStr = filePath.substring(filePath.lastIndexOf("/") + 1);
|
||||
try {
|
||||
Long ossId = Long.parseLong(ossIdStr);
|
||||
sysOssService.deleteWithValidByIds(List.of(ossId), true);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法从文件路径中解析ossId: {}", filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank(attachment.getThumbnailPath())) {
|
||||
OssFactory.instance().delete(attachment.getThumbnailPath());
|
||||
// 从缩略图路径中提取ossId
|
||||
String thumbnailPath = attachment.getThumbnailPath();
|
||||
if (thumbnailPath.contains("/resource/oss/download/")) {
|
||||
String ossIdStr = thumbnailPath.substring(thumbnailPath.lastIndexOf("/") + 1);
|
||||
try {
|
||||
Long ossId = Long.parseLong(ossIdStr);
|
||||
sysOssService.deleteWithValidByIds(List.of(ossId), true);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("无法从缩略图路径中解析ossId: {}", thumbnailPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("删除OSS文件失败: {}", e.getMessage());
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<groupId>org.dromara</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-stgl</artifactId>
|
||||
|
||||
<description>
|
||||
社团管理模块
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 安全模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- web服务 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- excel -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-excel</artifactId>
|
||||
</dependency>
|
||||
<!-- Apache POI for Excel export -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.2.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 多租户 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 幂等性 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-idempotent</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 日志记录 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据翻译 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-translation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- OSS云存储 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-oss</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 接口文档 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.stgl.domain.vo.StglClubVo;
|
||||
import org.dromara.stgl.domain.bo.StglClubBo;
|
||||
import org.dromara.stgl.service.IStglClubService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
* 社团信息管理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/club")
|
||||
@Tag(name = "社团信息管理", description = "社团信息管理")
|
||||
public class StglClubController extends BaseController {
|
||||
|
||||
private final IStglClubService stglClubService;
|
||||
|
||||
/**
|
||||
* 查询社团信息列表
|
||||
*/
|
||||
@Operation(summary = "查询社团信息列表")
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<StglClubVo> list(StglClubBo bo, PageQuery pageQuery) {
|
||||
return stglClubService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出社团信息列表
|
||||
*/
|
||||
@Operation(summary = "导出社团信息列表")
|
||||
@SaCheckPermission("stgl:club:export")
|
||||
@Log(title = "社团信息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(StglClubBo bo, HttpServletResponse response) {
|
||||
List<StglClubVo> list = stglClubService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "社团信息", StglClubVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团信息详细信息
|
||||
*/
|
||||
@Operation(summary = "获取社团信息详细信息")
|
||||
@SaCheckPermission("stgl:club:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<StglClubVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(stglClubService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团信息
|
||||
*/
|
||||
@Operation(summary = "新增社团信息")
|
||||
@SaCheckPermission("stgl:club:add")
|
||||
@Log(title = "社团信息", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglClubBo bo) {
|
||||
return toAjax(stglClubService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团信息
|
||||
*/
|
||||
@Operation(summary = "修改社团信息")
|
||||
@SaCheckPermission("stgl:club:edit")
|
||||
@Log(title = "社团信息", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglClubBo bo) {
|
||||
return toAjax(stglClubService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除社团信息
|
||||
*/
|
||||
@Operation(summary = "删除社团信息")
|
||||
@SaCheckPermission("stgl:club:remove")
|
||||
@Log(title = "社团信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(stglClubService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询可用的社团选项
|
||||
*/
|
||||
@Operation(summary = "查询可用的社团选项")
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/options")
|
||||
public R<List<StglClubVo>> getOptions() {
|
||||
return R.ok(stglClubService.queryAvailableOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据社团类型查询社团列表
|
||||
*/
|
||||
@Operation(summary = "根据社团类型查询社团列表")
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/listByType/{clubType}")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubType", description = "社团类型", required = true)
|
||||
})
|
||||
public R<List<StglClubVo>> listByType(@PathVariable String clubType) {
|
||||
return R.ok(stglClubService.queryByClubType(clubType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我管理的社团列表
|
||||
*/
|
||||
@Operation(summary = "查询我管理的社团列表")
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/myClubs")
|
||||
public R<List<StglClubVo>> getMyClubs() {
|
||||
return R.ok(stglClubService.queryMyClubs());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查社团名称是否重复
|
||||
*/
|
||||
@Operation(summary = "检查社团名称是否重复")
|
||||
@SaCheckPermission("stgl:club:list")
|
||||
@GetMapping("/checkClubNameUnique")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubName", description = "社团名称", required = true),
|
||||
@Parameter(name = "excludeId", description = "排除的ID", required = false)
|
||||
})
|
||||
public R<Boolean> checkClubNameUnique(@RequestParam String clubName,
|
||||
@RequestParam(required = false) Long excludeId) {
|
||||
return R.ok(stglClubService.checkClubNameUnique(clubName, excludeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用/禁用社团
|
||||
*/
|
||||
@Operation(summary = "启用/禁用社团")
|
||||
@SaCheckPermission("stgl:club:edit")
|
||||
@Log(title = "社团信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/changeStatus")
|
||||
@Parameters({
|
||||
@Parameter(name = "id", description = "社团ID", required = true),
|
||||
@Parameter(name = "status", description = "状态", required = true)
|
||||
})
|
||||
public R<Void> changeStatus(@RequestParam Long id, @RequestParam Integer status) {
|
||||
return toAjax(stglClubService.changeStatus(id, status));
|
||||
}
|
||||
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.stgl.domain.vo.StglClubRegisterVo;
|
||||
import org.dromara.stgl.service.IStglClubRegisterService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
* 社团报名大厅
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/register")
|
||||
@Tag(name = "社团报名大厅", description = "社团报名大厅")
|
||||
public class StglClubRegisterController extends BaseController {
|
||||
|
||||
private final IStglClubRegisterService stglClubRegisterService;
|
||||
|
||||
/**
|
||||
* 查询社团报名大厅列表
|
||||
*/
|
||||
@Operation(summary = "查询社团报名大厅列表")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<StglClubRegisterVo> list(@RequestParam(required = false) String clubType,
|
||||
@RequestParam(required = false) String clubName,
|
||||
PageQuery pageQuery) {
|
||||
return stglClubRegisterService.queryPageList(clubType, clubName, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团报名大厅列表(不分页)
|
||||
*/
|
||||
@Operation(summary = "查询社团报名大厅列表(不分页)")
|
||||
@GetMapping("/listAll")
|
||||
public R<List<StglClubRegisterVo>> listAll(@RequestParam(required = false) String clubType,
|
||||
@RequestParam(required = false) String clubName) {
|
||||
return R.ok(stglClubRegisterService.queryList(clubType, clubName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团详细信息
|
||||
*/
|
||||
@Operation(summary = "获取社团详细信息")
|
||||
@GetMapping("/{clubId}")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true)
|
||||
})
|
||||
public R<StglClubRegisterVo> getClubDetail(@PathVariable Long clubId) {
|
||||
return R.ok(stglClubRegisterService.queryClubDetail(clubId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 报名加入社团
|
||||
*/
|
||||
@Operation(summary = "报名加入社团")
|
||||
@SaCheckPermission("stgl:register:join")
|
||||
@Log(title = "社团报名", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/join/{clubId}")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true)
|
||||
})
|
||||
public R<Void> registerClub(@PathVariable Long clubId) {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
return toAjax(stglClubRegisterService.registerClub(clubId, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出社团
|
||||
*/
|
||||
@Operation(summary = "退出社团")
|
||||
@SaCheckPermission("stgl:register:quit")
|
||||
@Log(title = "社团退出", businessType = BusinessType.UPDATE)
|
||||
@PostMapping("/quit/{clubId}")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true)
|
||||
})
|
||||
public R<Void> quitClub(@PathVariable Long clubId) {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
return toAjax(stglClubRegisterService.quitClub(clubId, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我参与的社团列表
|
||||
*/
|
||||
@Operation(summary = "查询我参与的社团列表")
|
||||
@SaCheckPermission("stgl:register:list")
|
||||
@GetMapping("/myClubs")
|
||||
public R<List<StglClubRegisterVo>> getMyClubs() {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
return R.ok(stglClubRegisterService.queryMyClubs(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已报名某个社团
|
||||
*/
|
||||
@Operation(summary = "检查是否已报名某个社团")
|
||||
@GetMapping("/checkRegistered/{clubId}")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true)
|
||||
})
|
||||
public R<Boolean> checkRegistered(@PathVariable Long clubId) {
|
||||
try {
|
||||
Long userId = LoginHelper.getUserId();
|
||||
return R.ok(stglClubRegisterService.checkRegistered(clubId, userId));
|
||||
} catch (Exception e) {
|
||||
// 未登录用户
|
||||
return R.ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询推荐社团
|
||||
*/
|
||||
@Operation(summary = "查询推荐社团")
|
||||
@GetMapping("/recommend")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubType", description = "社团类型", required = false),
|
||||
@Parameter(name = "limit", description = "推荐数量", required = false)
|
||||
})
|
||||
public R<List<StglClubRegisterVo>> getRecommendClubs(@RequestParam(required = false) String clubType,
|
||||
@RequestParam(required = false, defaultValue = "6") Integer limit) {
|
||||
return R.ok(stglClubRegisterService.queryRecommendClubs(clubType, limit));
|
||||
}
|
||||
|
||||
}
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
package org.dromara.stgl.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.stgl.domain.vo.StglMemberVo;
|
||||
import org.dromara.stgl.domain.bo.StglMemberBo;
|
||||
import org.dromara.stgl.service.IStglMemberService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
/**
|
||||
* 社团成员管理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/stgl/member")
|
||||
@Tag(name = "社团成员管理", description = "社团成员管理")
|
||||
public class StglMemberController extends BaseController {
|
||||
|
||||
private final IStglMemberService stglMemberService;
|
||||
|
||||
/**
|
||||
* 查询社团成员列表
|
||||
*/
|
||||
@Operation(summary = "查询社团成员列表")
|
||||
@SaCheckPermission("stgl:member:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<StglMemberVo> list(StglMemberBo bo, PageQuery pageQuery) {
|
||||
return stglMemberService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出社团成员列表
|
||||
*/
|
||||
@Operation(summary = "导出社团成员列表")
|
||||
@SaCheckPermission("stgl:member:export")
|
||||
@Log(title = "社团成员", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(StglMemberBo bo, HttpServletResponse response) {
|
||||
List<StglMemberVo> list = stglMemberService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "社团成员", StglMemberVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取社团成员详细信息
|
||||
*/
|
||||
@Operation(summary = "获取社团成员详细信息")
|
||||
@SaCheckPermission("stgl:member:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<StglMemberVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(stglMemberService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团成员
|
||||
*/
|
||||
@Operation(summary = "新增社团成员")
|
||||
@SaCheckPermission("stgl:member:add")
|
||||
@Log(title = "社团成员", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody StglMemberBo bo) {
|
||||
return toAjax(stglMemberService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团成员
|
||||
*/
|
||||
@Operation(summary = "修改社团成员")
|
||||
@SaCheckPermission("stgl:member:edit")
|
||||
@Log(title = "社团成员", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody StglMemberBo bo) {
|
||||
return toAjax(stglMemberService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除社团成员
|
||||
*/
|
||||
@Operation(summary = "删除社团成员")
|
||||
@SaCheckPermission("stgl:member:remove")
|
||||
@Log(title = "社团成员", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(stglMemberService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据社团ID查询成员列表
|
||||
*/
|
||||
@Operation(summary = "根据社团ID查询成员列表")
|
||||
@SaCheckPermission("stgl:member:list")
|
||||
@GetMapping("/club/{clubId}")
|
||||
@Parameters({
|
||||
@Parameter(name = "clubId", description = "社团ID", required = true)
|
||||
})
|
||||
public R<List<StglMemberVo>> getByClubId(@PathVariable Long clubId) {
|
||||
return R.ok(stglMemberService.queryByClubId(clubId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询参与的社团列表
|
||||
*/
|
||||
@Operation(summary = "根据用户ID查询参与的社团列表")
|
||||
@SaCheckPermission("stgl:member:list")
|
||||
@GetMapping("/user/{userId}")
|
||||
@Parameters({
|
||||
@Parameter(name = "userId", description = "用户ID", required = true)
|
||||
})
|
||||
public R<List<StglMemberVo>> getByUserId(@PathVariable Long userId) {
|
||||
return R.ok(stglMemberService.queryByUserId(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否已是某个社团/队伍的成员
|
||||
*/
|
||||
@Operation(summary = "检查用户是否已是某个社团/队伍的成员")
|
||||
@SaCheckPermission("stgl:member:list")
|
||||
@GetMapping("/checkMemberExists")
|
||||
@Parameters({
|
||||
@Parameter(name = "memberType", description = "成员类型", required = true),
|
||||
@Parameter(name = "relationId", description = "关联ID", required = true),
|
||||
@Parameter(name = "userId", description = "用户ID", required = true)
|
||||
})
|
||||
public R<Boolean> checkMemberExists(@RequestParam Integer memberType,
|
||||
@RequestParam Long relationId,
|
||||
@RequestParam Long userId) {
|
||||
return R.ok(stglMemberService.checkMemberExists(memberType, relationId, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加成员
|
||||
*/
|
||||
@Operation(summary = "批量添加成员")
|
||||
@SaCheckPermission("stgl:member:add")
|
||||
@Log(title = "社团成员", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/batchAdd")
|
||||
@Parameters({
|
||||
@Parameter(name = "memberType", description = "成员类型", required = true),
|
||||
@Parameter(name = "relationId", description = "关联ID", required = true),
|
||||
@Parameter(name = "userIds", description = "用户ID列表", required = true),
|
||||
@Parameter(name = "roleType", description = "角色类型", required = false)
|
||||
})
|
||||
public R<Void> batchAddMembers(@RequestParam Integer memberType,
|
||||
@RequestParam Long relationId,
|
||||
@RequestParam List<Long> userIds,
|
||||
@RequestParam(required = false) Integer roleType) {
|
||||
return toAjax(stglMemberService.batchAddMembers(memberType, relationId, userIds, roleType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新成员角色
|
||||
*/
|
||||
@Operation(summary = "更新成员角色")
|
||||
@SaCheckPermission("stgl:member:edit")
|
||||
@Log(title = "社团成员", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/updateRole")
|
||||
@Parameters({
|
||||
@Parameter(name = "id", description = "成员ID", required = true),
|
||||
@Parameter(name = "roleType", description = "角色类型", required = true)
|
||||
})
|
||||
public R<Void> updateMemberRole(@RequestParam Long id, @RequestParam Integer roleType) {
|
||||
return toAjax(stglMemberService.updateMemberRole(id, roleType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出社团/队伍
|
||||
*/
|
||||
@Operation(summary = "退出社团/队伍")
|
||||
@SaCheckPermission("stgl:member:edit")
|
||||
@Log(title = "社团成员", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/quit/{id}")
|
||||
@Parameters({
|
||||
@Parameter(name = "id", description = "成员ID", required = true)
|
||||
})
|
||||
public R<Void> quitMember(@PathVariable Long id) {
|
||||
return toAjax(stglMemberService.quitMember(id));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.dromara.stgl.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团信息对象 stgl_club
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("stgl_club")
|
||||
public class StglClub extends TenantEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
private String clubName;
|
||||
|
||||
/**
|
||||
* 社团类型
|
||||
*/
|
||||
private String clubType;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
private Date establishDate;
|
||||
|
||||
/**
|
||||
* 社团简介(500字以内)
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 电话
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* logo图片路径
|
||||
*/
|
||||
private String logoUrl;
|
||||
|
||||
/**
|
||||
* 社长姓名
|
||||
*/
|
||||
private String presidentName;
|
||||
|
||||
/**
|
||||
* 社长学号
|
||||
*/
|
||||
private String presidentStudentNo;
|
||||
|
||||
/**
|
||||
* 社长院系
|
||||
*/
|
||||
private String presidentDept;
|
||||
|
||||
/**
|
||||
* 社长专业
|
||||
*/
|
||||
private String presidentMajor;
|
||||
|
||||
/**
|
||||
* 社长班级
|
||||
*/
|
||||
private String presidentClass;
|
||||
|
||||
/**
|
||||
* 社长联系方式
|
||||
*/
|
||||
private String presidentPhone;
|
||||
|
||||
/**
|
||||
* 副社长姓名
|
||||
*/
|
||||
private String vicePresidentName;
|
||||
|
||||
/**
|
||||
* 副社长学号
|
||||
*/
|
||||
private String vicePresidentStudentNo;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师所属院系
|
||||
*/
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 成员规模上限
|
||||
*/
|
||||
private Integer memberLimit;
|
||||
|
||||
/**
|
||||
* 组织架构(部门设置及职责)
|
||||
*/
|
||||
private String departments;
|
||||
|
||||
/**
|
||||
* 招新周期
|
||||
*/
|
||||
private String recruitCycle;
|
||||
|
||||
/**
|
||||
* 招新时间
|
||||
*/
|
||||
private String recruitTime;
|
||||
|
||||
/**
|
||||
* 活动频率
|
||||
*/
|
||||
private String activityFrequency;
|
||||
|
||||
/**
|
||||
* 经费来源(多选)
|
||||
*/
|
||||
private String fundingSources;
|
||||
|
||||
/**
|
||||
* 章程文档路径
|
||||
*/
|
||||
private String charterUrl;
|
||||
|
||||
/**
|
||||
* 状态(1-正常 0-停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package org.dromara.stgl.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团成员对象 stgl_member
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("stgl_member")
|
||||
public class StglMember extends TenantEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 成员类型(1-社团成员 2-志愿者)
|
||||
*/
|
||||
private Integer memberType;
|
||||
|
||||
/**
|
||||
* 关联ID(社团ID或志愿者队伍ID)
|
||||
*/
|
||||
private Long relationId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 角色类型(1-社长 2-副社长 3-成员)
|
||||
*/
|
||||
private Integer roleType;
|
||||
|
||||
/**
|
||||
* 加入时间
|
||||
*/
|
||||
private Date joinTime;
|
||||
|
||||
/**
|
||||
* 状态(1-正常 0-退出)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
package org.dromara.stgl.domain.bo;
|
||||
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团信息业务对象 stgl_club
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = StglClub.class, reverseConvertGenerate = false)
|
||||
public class StglClubBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
@NotBlank(message = "社团名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 100, message = "社团名称长度不能超过100个字符")
|
||||
private String clubName;
|
||||
|
||||
/**
|
||||
* 社团类型
|
||||
*/
|
||||
@NotBlank(message = "社团类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Size(max = 50, message = "社团类型长度不能超过50个字符")
|
||||
private String clubType;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
private Date establishDate;
|
||||
|
||||
/**
|
||||
* 社团简介(500字以内)
|
||||
*/
|
||||
@Size(max = 500, message = "社团简介长度不能超过500个字符")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Email(message = "邮箱格式不正确")
|
||||
@Size(max = 100, message = "邮箱长度不能超过100个字符")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 电话
|
||||
*/
|
||||
@Pattern(regexp = "^[0-9-]+$", message = "电话格式不正确")
|
||||
@Size(max = 20, message = "电话长度不能超过20个字符")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* logo图片路径
|
||||
*/
|
||||
@Size(max = 500, message = "logo图片路径长度不能超过500个字符")
|
||||
private String logoUrl;
|
||||
|
||||
/**
|
||||
* 社长姓名
|
||||
*/
|
||||
@Size(max = 50, message = "社长姓名长度不能超过50个字符")
|
||||
private String presidentName;
|
||||
|
||||
/**
|
||||
* 社长学号
|
||||
*/
|
||||
@Size(max = 20, message = "社长学号长度不能超过20个字符")
|
||||
private String presidentStudentNo;
|
||||
|
||||
/**
|
||||
* 社长院系
|
||||
*/
|
||||
@Size(max = 100, message = "社长院系长度不能超过100个字符")
|
||||
private String presidentDept;
|
||||
|
||||
/**
|
||||
* 社长专业
|
||||
*/
|
||||
@Size(max = 100, message = "社长专业长度不能超过100个字符")
|
||||
private String presidentMajor;
|
||||
|
||||
/**
|
||||
* 社长班级
|
||||
*/
|
||||
@Size(max = 100, message = "社长班级长度不能超过100个字符")
|
||||
private String presidentClass;
|
||||
|
||||
/**
|
||||
* 社长联系方式
|
||||
*/
|
||||
@Pattern(regexp = "^[0-9-]+$", message = "社长联系方式格式不正确")
|
||||
@Size(max = 20, message = "社长联系方式长度不能超过20个字符")
|
||||
private String presidentPhone;
|
||||
|
||||
/**
|
||||
* 副社长姓名
|
||||
*/
|
||||
@Size(max = 50, message = "副社长姓名长度不能超过50个字符")
|
||||
private String vicePresidentName;
|
||||
|
||||
/**
|
||||
* 副社长学号
|
||||
*/
|
||||
@Size(max = 20, message = "副社长学号长度不能超过20个字符")
|
||||
private String vicePresidentStudentNo;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
@Size(max = 50, message = "指导老师姓名长度不能超过50个字符")
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师所属院系
|
||||
*/
|
||||
@Size(max = 100, message = "指导老师所属院系长度不能超过100个字符")
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 成员规模上限
|
||||
*/
|
||||
@Min(value = 0, message = "成员规模上限不能小于0")
|
||||
private Integer memberLimit;
|
||||
|
||||
/**
|
||||
* 组织架构(部门设置及职责)
|
||||
*/
|
||||
private String departments;
|
||||
|
||||
/**
|
||||
* 招新周期
|
||||
*/
|
||||
@Size(max = 50, message = "招新周期长度不能超过50个字符")
|
||||
private String recruitCycle;
|
||||
|
||||
/**
|
||||
* 招新时间
|
||||
*/
|
||||
@Size(max = 50, message = "招新时间长度不能超过50个字符")
|
||||
private String recruitTime;
|
||||
|
||||
/**
|
||||
* 活动频率
|
||||
*/
|
||||
@Size(max = 50, message = "活动频率长度不能超过50个字符")
|
||||
private String activityFrequency;
|
||||
|
||||
/**
|
||||
* 经费来源(多选)
|
||||
*/
|
||||
@Size(max = 200, message = "经费来源长度不能超过200个字符")
|
||||
private String fundingSources;
|
||||
|
||||
/**
|
||||
* 章程文档路径
|
||||
*/
|
||||
@Size(max = 500, message = "章程文档路径长度不能超过500个字符")
|
||||
private String charterUrl;
|
||||
|
||||
/**
|
||||
* 状态(1-正常 0-停用)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package org.dromara.stgl.domain.bo;
|
||||
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.dromara.stgl.domain.StglMember;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团成员业务对象 stgl_member
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = StglMember.class, reverseConvertGenerate = false)
|
||||
public class StglMemberBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "主键ID不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 成员类型(1-社团成员 2-志愿者)
|
||||
*/
|
||||
@NotNull(message = "成员类型不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
@Min(value = 1, message = "成员类型值无效")
|
||||
@Max(value = 2, message = "成员类型值无效")
|
||||
private Integer memberType;
|
||||
|
||||
/**
|
||||
* 关联ID(社团ID或志愿者队伍ID)
|
||||
*/
|
||||
@NotNull(message = "关联ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long relationId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@NotNull(message = "用户ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@Size(max = 20, message = "学号长度不能超过20个字符")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@Size(max = 50, message = "学生姓名长度不能超过50个字符")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 角色类型(1-社长 2-副社长 3-成员)
|
||||
*/
|
||||
@Min(value = 1, message = "角色类型值无效")
|
||||
@Max(value = 3, message = "角色类型值无效")
|
||||
private Integer roleType;
|
||||
|
||||
/**
|
||||
* 加入时间
|
||||
*/
|
||||
private Date joinTime;
|
||||
|
||||
/**
|
||||
* 状态(1-正常 0-退出)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团报名大厅视图对象
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
public class StglClubRegisterVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
private String clubName;
|
||||
|
||||
/**
|
||||
* 社团类型
|
||||
*/
|
||||
private String clubType;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date establishDate;
|
||||
|
||||
/**
|
||||
* 社团简介(500字以内)
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* logo图片路径
|
||||
*/
|
||||
private String logoUrl;
|
||||
|
||||
/**
|
||||
* 社长姓名
|
||||
*/
|
||||
private String presidentName;
|
||||
|
||||
/**
|
||||
* 社长院系
|
||||
*/
|
||||
private String presidentDept;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师所属院系
|
||||
*/
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 成员规模上限
|
||||
*/
|
||||
private Integer memberLimit;
|
||||
|
||||
/**
|
||||
* 当前成员数量
|
||||
*/
|
||||
private Integer currentMemberCount;
|
||||
|
||||
/**
|
||||
* 招新周期
|
||||
*/
|
||||
private String recruitCycle;
|
||||
|
||||
/**
|
||||
* 招新时间
|
||||
*/
|
||||
private String recruitTime;
|
||||
|
||||
/**
|
||||
* 活动频率
|
||||
*/
|
||||
private String activityFrequency;
|
||||
|
||||
/**
|
||||
* 是否已报名
|
||||
*/
|
||||
private Boolean hasRegistered;
|
||||
|
||||
/**
|
||||
* 报名状态(1-已报名 0-未报名)
|
||||
*/
|
||||
private Integer registrationStatus;
|
||||
|
||||
/**
|
||||
* 是否可报名(基于成员上限等条件)
|
||||
*/
|
||||
private Boolean canRegister;
|
||||
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团信息视图对象 stgl_club
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = StglClub.class)
|
||||
public class StglClubVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 社团名称
|
||||
*/
|
||||
@ExcelProperty(value = "社团名称")
|
||||
private String clubName;
|
||||
|
||||
/**
|
||||
* 社团类型
|
||||
*/
|
||||
@ExcelProperty(value = "社团类型")
|
||||
private String clubType;
|
||||
|
||||
/**
|
||||
* 成立日期
|
||||
*/
|
||||
@ExcelProperty(value = "成立日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date establishDate;
|
||||
|
||||
/**
|
||||
* 社团简介(500字以内)
|
||||
*/
|
||||
@ExcelProperty(value = "社团简介")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@ExcelProperty(value = "邮箱")
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 电话
|
||||
*/
|
||||
@ExcelProperty(value = "电话")
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* logo图片路径
|
||||
*/
|
||||
@ExcelProperty(value = "社团Logo")
|
||||
private String logoUrl;
|
||||
|
||||
/**
|
||||
* 社长姓名
|
||||
*/
|
||||
@ExcelProperty(value = "社长姓名")
|
||||
private String presidentName;
|
||||
|
||||
/**
|
||||
* 社长学号
|
||||
*/
|
||||
@ExcelProperty(value = "社长学号")
|
||||
private String presidentStudentNo;
|
||||
|
||||
/**
|
||||
* 社长院系
|
||||
*/
|
||||
@ExcelProperty(value = "社长院系")
|
||||
private String presidentDept;
|
||||
|
||||
/**
|
||||
* 社长专业
|
||||
*/
|
||||
@ExcelProperty(value = "社长专业")
|
||||
private String presidentMajor;
|
||||
|
||||
/**
|
||||
* 社长班级
|
||||
*/
|
||||
@ExcelProperty(value = "社长班级")
|
||||
private String presidentClass;
|
||||
|
||||
/**
|
||||
* 社长联系方式
|
||||
*/
|
||||
@ExcelProperty(value = "社长联系方式")
|
||||
private String presidentPhone;
|
||||
|
||||
/**
|
||||
* 副社长姓名
|
||||
*/
|
||||
@ExcelProperty(value = "副社长姓名")
|
||||
private String vicePresidentName;
|
||||
|
||||
/**
|
||||
* 副社长学号
|
||||
*/
|
||||
@ExcelProperty(value = "副社长学号")
|
||||
private String vicePresidentStudentNo;
|
||||
|
||||
/**
|
||||
* 指导老师姓名
|
||||
*/
|
||||
@ExcelProperty(value = "指导老师姓名")
|
||||
private String advisorName;
|
||||
|
||||
/**
|
||||
* 指导老师所属院系
|
||||
*/
|
||||
@ExcelProperty(value = "指导老师所属院系")
|
||||
private String advisorDept;
|
||||
|
||||
/**
|
||||
* 成员规模上限
|
||||
*/
|
||||
@ExcelProperty(value = "成员规模上限")
|
||||
private Integer memberLimit;
|
||||
|
||||
/**
|
||||
* 组织架构(部门设置及职责)
|
||||
*/
|
||||
@ExcelProperty(value = "组织架构")
|
||||
private String departments;
|
||||
|
||||
/**
|
||||
* 招新周期
|
||||
*/
|
||||
@ExcelProperty(value = "招新周期")
|
||||
private String recruitCycle;
|
||||
|
||||
/**
|
||||
* 招新时间
|
||||
*/
|
||||
@ExcelProperty(value = "招新时间")
|
||||
private String recruitTime;
|
||||
|
||||
/**
|
||||
* 活动频率
|
||||
*/
|
||||
@ExcelProperty(value = "活动频率")
|
||||
private String activityFrequency;
|
||||
|
||||
/**
|
||||
* 经费来源(多选)
|
||||
*/
|
||||
@ExcelProperty(value = "经费来源")
|
||||
private String fundingSources;
|
||||
|
||||
/**
|
||||
* 章程文档路径
|
||||
*/
|
||||
@ExcelProperty(value = "章程文档")
|
||||
private String charterUrl;
|
||||
|
||||
/**
|
||||
* 状态(1-正常 0-停用)
|
||||
*/
|
||||
@ExcelProperty(value = "状态")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package org.dromara.stgl.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import org.dromara.stgl.domain.StglMember;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 社团成员视图对象 stgl_member
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = StglMember.class)
|
||||
public class StglMemberVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 成员类型(1-社团成员 2-志愿者)
|
||||
*/
|
||||
@ExcelProperty(value = "成员类型")
|
||||
private Integer memberType;
|
||||
|
||||
/**
|
||||
* 成员类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "成员类型名称")
|
||||
private String memberTypeName;
|
||||
|
||||
/**
|
||||
* 关联ID(社团ID或志愿者队伍ID)
|
||||
*/
|
||||
@ExcelProperty(value = "关联ID")
|
||||
private Long relationId;
|
||||
|
||||
/**
|
||||
* 关联名称(社团名称或志愿者队伍名称)
|
||||
*/
|
||||
@ExcelProperty(value = "所属组织")
|
||||
private String relationName;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@ExcelProperty(value = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@ExcelProperty(value = "学号")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@ExcelProperty(value = "学生姓名")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 角色类型(1-社长 2-副社长 3-成员)
|
||||
*/
|
||||
@ExcelProperty(value = "角色类型")
|
||||
private Integer roleType;
|
||||
|
||||
/**
|
||||
* 角色类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "角色名称")
|
||||
private String roleTypeName;
|
||||
|
||||
/**
|
||||
* 加入时间
|
||||
*/
|
||||
@ExcelProperty(value = "加入时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date joinTime;
|
||||
|
||||
/**
|
||||
* 状态(1-正常 0-退出)
|
||||
*/
|
||||
@ExcelProperty(value = "状态")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 状态名称
|
||||
*/
|
||||
@ExcelProperty(value = "状态名称")
|
||||
private String statusName;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ExcelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
import org.dromara.stgl.domain.vo.StglClubVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 社团信息Mapper接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface StglClubMapper extends BaseMapperPlus<StglClub, StglClubVo> {
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.dromara.stgl.mapper;
|
||||
|
||||
import org.dromara.stgl.domain.StglMember;
|
||||
import org.dromara.stgl.domain.vo.StglMemberVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 社团成员Mapper接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface StglMemberMapper extends BaseMapperPlus<StglMember, StglMemberVo> {
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.vo.StglClubRegisterVo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团报名大厅Service接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface IStglClubRegisterService {
|
||||
|
||||
/**
|
||||
* 分页查询社团报名大厅列表
|
||||
*
|
||||
* @param clubType 社团类型
|
||||
* @param clubName 社团名称
|
||||
* @param pageQuery 分页参数
|
||||
* @return 社团报名大厅分页列表
|
||||
*/
|
||||
TableDataInfo<StglClubRegisterVo> queryPageList(String clubType, String clubName, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询社团报名大厅列表
|
||||
*
|
||||
* @param clubType 社团类型
|
||||
* @param clubName 社团名称
|
||||
* @return 社团报名大厅列表
|
||||
*/
|
||||
List<StglClubRegisterVo> queryList(String clubType, String clubName);
|
||||
|
||||
/**
|
||||
* 查询社团详细信息(用于报名)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 社团详细信息
|
||||
*/
|
||||
StglClubRegisterVo queryClubDetail(Long clubId);
|
||||
|
||||
/**
|
||||
* 报名加入社团
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否报名成功
|
||||
*/
|
||||
Boolean registerClub(Long clubId, Long userId);
|
||||
|
||||
/**
|
||||
* 退出社团
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否退出成功
|
||||
*/
|
||||
Boolean quitClub(Long clubId, Long userId);
|
||||
|
||||
/**
|
||||
* 查询我参与的社团列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 社团列表
|
||||
*/
|
||||
List<StglClubRegisterVo> queryMyClubs(Long userId);
|
||||
|
||||
/**
|
||||
* 检查是否已报名某个社团
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否已报名
|
||||
*/
|
||||
Boolean checkRegistered(Long clubId, Long userId);
|
||||
|
||||
/**
|
||||
* 根据社团类型查询推荐社团
|
||||
*
|
||||
* @param clubType 社团类型
|
||||
* @param limit 推荐数量
|
||||
* @return 推荐社团列表
|
||||
*/
|
||||
List<StglClubRegisterVo> queryRecommendClubs(String clubType, Integer limit);
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.vo.StglClubVo;
|
||||
import org.dromara.stgl.domain.bo.StglClubBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团信息Service接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface IStglClubService {
|
||||
|
||||
/**
|
||||
* 查询社团信息
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 社团信息
|
||||
*/
|
||||
StglClubVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询社团信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 社团信息分页列表
|
||||
*/
|
||||
TableDataInfo<StglClubVo> queryPageList(StglClubBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的社团信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 社团信息列表
|
||||
*/
|
||||
List<StglClubVo> queryList(StglClubBo bo);
|
||||
|
||||
/**
|
||||
* 新增社团信息
|
||||
*
|
||||
* @param bo 社团信息
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(StglClubBo bo);
|
||||
|
||||
/**
|
||||
* 修改社团信息
|
||||
*
|
||||
* @param bo 社团信息
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(StglClubBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除社团信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 查询可用的社团选项
|
||||
*
|
||||
* @return 社团选项列表
|
||||
*/
|
||||
List<StglClubVo> queryAvailableOptions();
|
||||
|
||||
/**
|
||||
* 根据社团类型查询社团列表
|
||||
*
|
||||
* @param clubType 社团类型
|
||||
* @return 社团列表
|
||||
*/
|
||||
List<StglClubVo> queryByClubType(String clubType);
|
||||
|
||||
/**
|
||||
* 查询我管理的社团列表
|
||||
*
|
||||
* @return 社团列表
|
||||
*/
|
||||
List<StglClubVo> queryMyClubs();
|
||||
|
||||
/**
|
||||
* 检查社团名称是否重复
|
||||
*
|
||||
* @param clubName 社团名称
|
||||
* @param excludeId 排除的ID(修改时使用)
|
||||
* @return 是否重复
|
||||
*/
|
||||
Boolean checkClubNameUnique(String clubName, Long excludeId);
|
||||
|
||||
/**
|
||||
* 启用/禁用社团
|
||||
*
|
||||
* @param id 社团ID
|
||||
* @param status 状态
|
||||
* @return 是否操作成功
|
||||
*/
|
||||
Boolean changeStatus(Long id, Integer status);
|
||||
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
package org.dromara.stgl.service;
|
||||
|
||||
import org.dromara.stgl.domain.vo.StglMemberVo;
|
||||
import org.dromara.stgl.domain.bo.StglMemberBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 社团成员Service接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
public interface IStglMemberService {
|
||||
|
||||
/**
|
||||
* 查询社团成员
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 社团成员
|
||||
*/
|
||||
StglMemberVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询社团成员列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 社团成员分页列表
|
||||
*/
|
||||
TableDataInfo<StglMemberVo> queryPageList(StglMemberBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的社团成员列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 社团成员列表
|
||||
*/
|
||||
List<StglMemberVo> queryList(StglMemberBo bo);
|
||||
|
||||
/**
|
||||
* 新增社团成员
|
||||
*
|
||||
* @param bo 社团成员
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(StglMemberBo bo);
|
||||
|
||||
/**
|
||||
* 修改社团成员
|
||||
*
|
||||
* @param bo 社团成员
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(StglMemberBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除社团成员
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 根据社团ID查询成员列表
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 成员列表
|
||||
*/
|
||||
List<StglMemberVo> queryByClubId(Long clubId);
|
||||
|
||||
/**
|
||||
* 根据用户ID查询参与的社团列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 社团成员关系列表
|
||||
*/
|
||||
List<StglMemberVo> queryByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 检查用户是否已是某个社团/队伍的成员
|
||||
*
|
||||
* @param memberType 成员类型
|
||||
* @param relationId 关联ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否已是成员
|
||||
*/
|
||||
Boolean checkMemberExists(Integer memberType, Long relationId, Long userId);
|
||||
|
||||
/**
|
||||
* 批量添加成员
|
||||
*
|
||||
* @param memberType 成员类型
|
||||
* @param relationId 关联ID
|
||||
* @param userIds 用户ID列表
|
||||
* @param roleType 角色类型
|
||||
* @return 是否添加成功
|
||||
*/
|
||||
Boolean batchAddMembers(Integer memberType, Long relationId, List<Long> userIds, Integer roleType);
|
||||
|
||||
/**
|
||||
* 更新成员角色
|
||||
*
|
||||
* @param id 成员ID
|
||||
* @param roleType 角色类型
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
Boolean updateMemberRole(Long id, Integer roleType);
|
||||
|
||||
/**
|
||||
* 退出社团/队伍
|
||||
*
|
||||
* @param id 成员ID
|
||||
* @return 是否退出成功
|
||||
*/
|
||||
Boolean quitMember(Long id);
|
||||
|
||||
}
|
||||
+306
@@ -0,0 +1,306 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.stgl.domain.vo.StglClubRegisterVo;
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
import org.dromara.stgl.domain.StglMember;
|
||||
import org.dromara.stgl.mapper.StglClubMapper;
|
||||
import org.dromara.stgl.mapper.StglMemberMapper;
|
||||
import org.dromara.stgl.service.IStglClubRegisterService;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 社团报名大厅Service业务层处理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglClubRegisterServiceImpl implements IStglClubRegisterService {
|
||||
|
||||
private final StglClubMapper clubMapper;
|
||||
private final StglMemberMapper memberMapper;
|
||||
|
||||
/**
|
||||
* 分页查询社团报名大厅列表
|
||||
*
|
||||
* @param clubType 社团类型
|
||||
* @param clubName 社团名称
|
||||
* @param pageQuery 分页参数
|
||||
* @return 社团报名大厅分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglClubRegisterVo> queryPageList(String clubType, String clubName, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(clubType, clubName);
|
||||
Page<StglClub> page = clubMapper.selectPage(pageQuery.build(), lqw);
|
||||
|
||||
List<StglClubRegisterVo> voList = convertToRegisterVo(page.getRecords());
|
||||
|
||||
Page<StglClubRegisterVo> result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
|
||||
result.setRecords(voList);
|
||||
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团报名大厅列表
|
||||
*
|
||||
* @param clubType 社团类型
|
||||
* @param clubName 社团名称
|
||||
* @return 社团报名大厅列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubRegisterVo> queryList(String clubType, String clubName) {
|
||||
LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(clubType, clubName);
|
||||
List<StglClub> clubs = clubMapper.selectList(lqw);
|
||||
return convertToRegisterVo(clubs);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<StglClub> buildQueryWrapper(String clubType, String clubName) {
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglClub::getStatus, 1); // 只查询正常状态的社团
|
||||
lqw.eq(StringUtils.isNotBlank(clubType), StglClub::getClubType, clubType);
|
||||
lqw.like(StringUtils.isNotBlank(clubName), StglClub::getClubName, clubName);
|
||||
lqw.orderByDesc(StglClub::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
private List<StglClubRegisterVo> convertToRegisterVo(List<StglClub> clubs) {
|
||||
Long currentUserId = null;
|
||||
try {
|
||||
currentUserId = LoginHelper.getUserId();
|
||||
} catch (Exception e) {
|
||||
// 未登录用户
|
||||
}
|
||||
|
||||
final Long userId = currentUserId;
|
||||
|
||||
return clubs.stream().map(club -> {
|
||||
StglClubRegisterVo vo = new StglClubRegisterVo();
|
||||
vo.setId(club.getId());
|
||||
vo.setClubName(club.getClubName());
|
||||
vo.setClubType(club.getClubType());
|
||||
vo.setEstablishDate(club.getEstablishDate());
|
||||
vo.setDescription(club.getDescription());
|
||||
vo.setLogoUrl(club.getLogoUrl());
|
||||
vo.setPresidentName(club.getPresidentName());
|
||||
vo.setPresidentDept(club.getPresidentDept());
|
||||
vo.setAdvisorName(club.getAdvisorName());
|
||||
vo.setAdvisorDept(club.getAdvisorDept());
|
||||
vo.setMemberLimit(club.getMemberLimit());
|
||||
vo.setRecruitCycle(club.getRecruitCycle());
|
||||
vo.setRecruitTime(club.getRecruitTime());
|
||||
vo.setActivityFrequency(club.getActivityFrequency());
|
||||
|
||||
// 查询当前成员数量
|
||||
LambdaQueryWrapper<StglMember> memberCountLqw = Wrappers.lambdaQuery();
|
||||
memberCountLqw.eq(StglMember::getMemberType, 1);
|
||||
memberCountLqw.eq(StglMember::getRelationId, club.getId());
|
||||
memberCountLqw.eq(StglMember::getStatus, 1);
|
||||
long memberCount = memberMapper.selectCount(memberCountLqw);
|
||||
vo.setCurrentMemberCount((int) memberCount);
|
||||
|
||||
// 检查是否可报名
|
||||
boolean canRegister = club.getMemberLimit() == null || club.getMemberLimit() == 0 || memberCount < club.getMemberLimit();
|
||||
vo.setCanRegister(canRegister);
|
||||
|
||||
// 检查当前用户是否已报名
|
||||
if (userId != null) {
|
||||
LambdaQueryWrapper<StglMember> userMemberLqw = Wrappers.lambdaQuery();
|
||||
userMemberLqw.eq(StglMember::getMemberType, 1);
|
||||
userMemberLqw.eq(StglMember::getRelationId, club.getId());
|
||||
userMemberLqw.eq(StglMember::getUserId, userId);
|
||||
userMemberLqw.eq(StglMember::getStatus, 1);
|
||||
long registeredCount = memberMapper.selectCount(userMemberLqw);
|
||||
vo.setHasRegistered(registeredCount > 0);
|
||||
vo.setRegistrationStatus(registeredCount > 0 ? 1 : 0);
|
||||
} else {
|
||||
vo.setHasRegistered(false);
|
||||
vo.setRegistrationStatus(0);
|
||||
}
|
||||
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询社团详细信息(用于报名)
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 社团详细信息
|
||||
*/
|
||||
@Override
|
||||
public StglClubRegisterVo queryClubDetail(Long clubId) {
|
||||
StglClub club = clubMapper.selectById(clubId);
|
||||
if (club == null) {
|
||||
return null;
|
||||
}
|
||||
return convertToRegisterVo(List.of(club)).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 报名加入社团
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否报名成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean registerClub(Long clubId, Long userId) {
|
||||
// 检查社团是否存在
|
||||
StglClub club = clubMapper.selectById(clubId);
|
||||
if (club == null || club.getStatus() != 1) {
|
||||
throw new RuntimeException("社团不存在或已停用");
|
||||
}
|
||||
|
||||
// 检查是否已是成员
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglMember::getMemberType, 1);
|
||||
lqw.eq(StglMember::getRelationId, clubId);
|
||||
lqw.eq(StglMember::getUserId, userId);
|
||||
lqw.eq(StglMember::getStatus, 1);
|
||||
long count = memberMapper.selectCount(lqw);
|
||||
if (count > 0) {
|
||||
throw new RuntimeException("您已是该社团的成员");
|
||||
}
|
||||
|
||||
// 检查成员上限
|
||||
if (club.getMemberLimit() != null && club.getMemberLimit() > 0) {
|
||||
LambdaQueryWrapper<StglMember> memberLqw = Wrappers.lambdaQuery();
|
||||
memberLqw.eq(StglMember::getMemberType, 1);
|
||||
memberLqw.eq(StglMember::getRelationId, clubId);
|
||||
memberLqw.eq(StglMember::getStatus, 1);
|
||||
long memberCount = memberMapper.selectCount(memberLqw);
|
||||
if (memberCount >= club.getMemberLimit()) {
|
||||
throw new RuntimeException("该社团成员已满,无法加入");
|
||||
}
|
||||
}
|
||||
|
||||
// 创建成员记录
|
||||
StglMember member = new StglMember();
|
||||
member.setMemberType(1); // 社团成员
|
||||
member.setRelationId(clubId);
|
||||
member.setUserId(userId);
|
||||
member.setRoleType(3); // 普通成员
|
||||
member.setJoinTime(new Date());
|
||||
member.setStatus(1);
|
||||
|
||||
return memberMapper.insert(member) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出社团
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否退出成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean quitClub(Long clubId, Long userId) {
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglMember::getMemberType, 1);
|
||||
lqw.eq(StglMember::getRelationId, clubId);
|
||||
lqw.eq(StglMember::getUserId, userId);
|
||||
lqw.eq(StglMember::getStatus, 1);
|
||||
|
||||
StglMember member = memberMapper.selectOne(lqw);
|
||||
if (member == null) {
|
||||
throw new RuntimeException("您不是该社团的成员");
|
||||
}
|
||||
|
||||
// 检查是否是社长或副社长
|
||||
if (member.getRoleType() != null && member.getRoleType() <= 2) {
|
||||
throw new RuntimeException("社长和副社长不能直接退出,请先转让职务");
|
||||
}
|
||||
|
||||
member.setStatus(0);
|
||||
return memberMapper.updateById(member) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我参与的社团列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 社团列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubRegisterVo> queryMyClubs(Long userId) {
|
||||
// 查询用户参与的社团ID
|
||||
LambdaQueryWrapper<StglMember> memberLqw = Wrappers.lambdaQuery();
|
||||
memberLqw.eq(StglMember::getMemberType, 1);
|
||||
memberLqw.eq(StglMember::getUserId, userId);
|
||||
memberLqw.eq(StglMember::getStatus, 1);
|
||||
List<StglMember> members = memberMapper.selectList(memberLqw);
|
||||
|
||||
if (members.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<Long> clubIds = members.stream().map(StglMember::getRelationId).collect(Collectors.toList());
|
||||
|
||||
// 查询社团信息
|
||||
LambdaQueryWrapper<StglClub> clubLqw = Wrappers.lambdaQuery();
|
||||
clubLqw.in(StglClub::getId, clubIds);
|
||||
clubLqw.eq(StglClub::getStatus, 1);
|
||||
clubLqw.orderByDesc(StglClub::getCreateTime);
|
||||
List<StglClub> clubs = clubMapper.selectList(clubLqw);
|
||||
|
||||
return convertToRegisterVo(clubs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已报名某个社团
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否已报名
|
||||
*/
|
||||
@Override
|
||||
public Boolean checkRegistered(Long clubId, Long userId) {
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglMember::getMemberType, 1);
|
||||
lqw.eq(StglMember::getRelationId, clubId);
|
||||
lqw.eq(StglMember::getUserId, userId);
|
||||
lqw.eq(StglMember::getStatus, 1);
|
||||
long count = memberMapper.selectCount(lqw);
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据社团类型查询推荐社团
|
||||
*
|
||||
* @param clubType 社团类型
|
||||
* @param limit 推荐数量
|
||||
* @return 推荐社团列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubRegisterVo> queryRecommendClubs(String clubType, Integer limit) {
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglClub::getStatus, 1);
|
||||
if (StringUtils.isNotBlank(clubType)) {
|
||||
lqw.eq(StglClub::getClubType, clubType);
|
||||
}
|
||||
lqw.orderByDesc(StglClub::getCreateTime);
|
||||
if (limit != null && limit > 0) {
|
||||
lqw.last("LIMIT " + limit);
|
||||
}
|
||||
|
||||
List<StglClub> clubs = clubMapper.selectList(lqw);
|
||||
return convertToRegisterVo(clubs);
|
||||
}
|
||||
|
||||
}
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.stgl.domain.bo.StglClubBo;
|
||||
import org.dromara.stgl.domain.vo.StglClubVo;
|
||||
import org.dromara.stgl.domain.StglClub;
|
||||
import org.dromara.stgl.mapper.StglClubMapper;
|
||||
import org.dromara.stgl.service.IStglClubService;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 社团信息Service业务层处理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglClubServiceImpl implements IStglClubService {
|
||||
|
||||
private final StglClubMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询社团信息
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 社团信息
|
||||
*/
|
||||
@Override
|
||||
public StglClubVo queryById(Long id){
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询社团信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 社团信息分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglClubVo> queryPageList(StglClubBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(bo);
|
||||
Page<StglClubVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的社团信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 社团信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubVo> queryList(StglClubBo bo) {
|
||||
LambdaQueryWrapper<StglClub> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<StglClub> buildQueryWrapper(StglClubBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
lqw.like(StringUtils.isNotBlank(bo.getClubName()), StglClub::getClubName, bo.getClubName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getClubType()), StglClub::getClubType, bo.getClubType());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getPresidentName()), StglClub::getPresidentName, bo.getPresidentName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getPresidentStudentNo()), StglClub::getPresidentStudentNo, bo.getPresidentStudentNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getAdvisorName()), StglClub::getAdvisorName, bo.getAdvisorName());
|
||||
lqw.eq(bo.getStatus() != null, StglClub::getStatus, bo.getStatus());
|
||||
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
|
||||
StglClub::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
||||
lqw.orderByDesc(StglClub::getCreateTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团信息
|
||||
*
|
||||
* @param bo 社团信息
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(StglClubBo bo) {
|
||||
StglClub add = MapstructUtils.convert(bo, StglClub.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团信息
|
||||
*
|
||||
* @param bo 社团信息
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(StglClubBo bo) {
|
||||
StglClub update = MapstructUtils.convert(bo, StglClub.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(StglClub entity){
|
||||
// 检查社团名称是否重复
|
||||
if (StringUtils.isNotBlank(entity.getClubName())) {
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglClub::getClubName, entity.getClubName());
|
||||
if (entity.getId() != null) {
|
||||
lqw.ne(StglClub::getId, entity.getId());
|
||||
}
|
||||
long count = baseMapper.selectCount(lqw);
|
||||
if (count > 0) {
|
||||
throw new RuntimeException("社团名称已存在,请重新输入");
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认状态
|
||||
if (entity.getStatus() == null) {
|
||||
entity.setStatus(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除社团信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
// 可以添加删除前的业务校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询可用的社团选项
|
||||
*
|
||||
* @return 社团选项列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubVo> queryAvailableOptions() {
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglClub::getStatus, 1);
|
||||
lqw.select(StglClub::getId, StglClub::getClubName, StglClub::getClubType);
|
||||
lqw.orderByAsc(StglClub::getClubName);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据社团类型查询社团列表
|
||||
*
|
||||
* @param clubType 社团类型
|
||||
* @return 社团列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubVo> queryByClubType(String clubType) {
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglClub::getClubType, clubType);
|
||||
lqw.eq(StglClub::getStatus, 1);
|
||||
lqw.orderByAsc(StglClub::getClubName);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我管理的社团列表
|
||||
*
|
||||
* @return 社团列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglClubVo> queryMyClubs() {
|
||||
// 根据当前用户查询其管理的社团
|
||||
Long userId = LoginHelper.getUserId();
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglClub::getCreateBy, userId);
|
||||
lqw.eq(StglClub::getStatus, 1);
|
||||
lqw.orderByDesc(StglClub::getCreateTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查社团名称是否重复
|
||||
*
|
||||
* @param clubName 社团名称
|
||||
* @param excludeId 排除的ID(修改时使用)
|
||||
* @return 是否重复
|
||||
*/
|
||||
@Override
|
||||
public Boolean checkClubNameUnique(String clubName, Long excludeId) {
|
||||
LambdaQueryWrapper<StglClub> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglClub::getClubName, clubName);
|
||||
if (excludeId != null) {
|
||||
lqw.ne(StglClub::getId, excludeId);
|
||||
}
|
||||
long count = baseMapper.selectCount(lqw);
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启用/禁用社团
|
||||
*
|
||||
* @param id 社团ID
|
||||
* @param status 状态
|
||||
* @return 是否操作成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean changeStatus(Long id, Integer status) {
|
||||
StglClub club = new StglClub();
|
||||
club.setId(id);
|
||||
club.setStatus(status);
|
||||
return baseMapper.updateById(club) > 0;
|
||||
}
|
||||
|
||||
}
|
||||
+272
@@ -0,0 +1,272 @@
|
||||
package org.dromara.stgl.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.dromara.stgl.domain.bo.StglMemberBo;
|
||||
import org.dromara.stgl.domain.vo.StglMemberVo;
|
||||
import org.dromara.stgl.domain.StglMember;
|
||||
import org.dromara.stgl.mapper.StglMemberMapper;
|
||||
import org.dromara.stgl.service.IStglMemberService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 社团成员Service业务层处理
|
||||
*
|
||||
* @author Cursor AI
|
||||
* @date 2025-01-15
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class StglMemberServiceImpl implements IStglMemberService {
|
||||
|
||||
private final StglMemberMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询社团成员
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 社团成员
|
||||
*/
|
||||
@Override
|
||||
public StglMemberVo queryById(Long id){
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询社团成员列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 社团成员分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<StglMemberVo> queryPageList(StglMemberBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<StglMember> lqw = buildQueryWrapper(bo);
|
||||
Page<StglMemberVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的社团成员列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 社团成员列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglMemberVo> queryList(StglMemberBo bo) {
|
||||
LambdaQueryWrapper<StglMember> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<StglMember> buildQueryWrapper(StglMemberBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getMemberType() != null, StglMember::getMemberType, bo.getMemberType());
|
||||
lqw.eq(bo.getRelationId() != null, StglMember::getRelationId, bo.getRelationId());
|
||||
lqw.eq(bo.getUserId() != null, StglMember::getUserId, bo.getUserId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentNo()), StglMember::getStudentNo, bo.getStudentNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), StglMember::getStudentName, bo.getStudentName());
|
||||
lqw.eq(bo.getRoleType() != null, StglMember::getRoleType, bo.getRoleType());
|
||||
lqw.eq(bo.getStatus() != null, StglMember::getStatus, bo.getStatus());
|
||||
lqw.between(params.get("beginJoinTime") != null && params.get("endJoinTime") != null,
|
||||
StglMember::getJoinTime, params.get("beginJoinTime"), params.get("endJoinTime"));
|
||||
lqw.orderByDesc(StglMember::getJoinTime);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增社团成员
|
||||
*
|
||||
* @param bo 社团成员
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(StglMemberBo bo) {
|
||||
StglMember add = MapstructUtils.convert(bo, StglMember.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改社团成员
|
||||
*
|
||||
* @param bo 社团成员
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(StglMemberBo bo) {
|
||||
StglMember update = MapstructUtils.convert(bo, StglMember.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(StglMember entity){
|
||||
// 检查用户是否已是成员
|
||||
if (entity.getMemberType() != null && entity.getRelationId() != null && entity.getUserId() != null) {
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglMember::getMemberType, entity.getMemberType());
|
||||
lqw.eq(StglMember::getRelationId, entity.getRelationId());
|
||||
lqw.eq(StglMember::getUserId, entity.getUserId());
|
||||
if (entity.getId() != null) {
|
||||
lqw.ne(StglMember::getId, entity.getId());
|
||||
}
|
||||
long count = baseMapper.selectCount(lqw);
|
||||
if (count > 0) {
|
||||
throw new RuntimeException("用户已是该组织的成员,不能重复添加");
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认值
|
||||
if (entity.getJoinTime() == null) {
|
||||
entity.setJoinTime(new Date());
|
||||
}
|
||||
if (entity.getStatus() == null) {
|
||||
entity.setStatus(1);
|
||||
}
|
||||
if (entity.getRoleType() == null) {
|
||||
entity.setRoleType(3); // 默认为普通成员
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除社团成员
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
// 可以添加删除前的业务校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据社团ID查询成员列表
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @return 成员列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglMemberVo> queryByClubId(Long clubId) {
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglMember::getMemberType, 1); // 社团成员
|
||||
lqw.eq(StglMember::getRelationId, clubId);
|
||||
lqw.eq(StglMember::getStatus, 1);
|
||||
lqw.orderByAsc(StglMember::getRoleType).orderByAsc(StglMember::getJoinTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询参与的社团列表
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 社团成员关系列表
|
||||
*/
|
||||
@Override
|
||||
public List<StglMemberVo> queryByUserId(Long userId) {
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglMember::getUserId, userId);
|
||||
lqw.eq(StglMember::getStatus, 1);
|
||||
lqw.orderByDesc(StglMember::getJoinTime);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否已是某个社团/队伍的成员
|
||||
*
|
||||
* @param memberType 成员类型
|
||||
* @param relationId 关联ID
|
||||
* @param userId 用户ID
|
||||
* @return 是否已是成员
|
||||
*/
|
||||
@Override
|
||||
public Boolean checkMemberExists(Integer memberType, Long relationId, Long userId) {
|
||||
LambdaQueryWrapper<StglMember> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StglMember::getMemberType, memberType);
|
||||
lqw.eq(StglMember::getRelationId, relationId);
|
||||
lqw.eq(StglMember::getUserId, userId);
|
||||
lqw.eq(StglMember::getStatus, 1);
|
||||
long count = baseMapper.selectCount(lqw);
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加成员
|
||||
*
|
||||
* @param memberType 成员类型
|
||||
* @param relationId 关联ID
|
||||
* @param userIds 用户ID列表
|
||||
* @param roleType 角色类型
|
||||
* @return 是否添加成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean batchAddMembers(Integer memberType, Long relationId, List<Long> userIds, Integer roleType) {
|
||||
Date now = new Date();
|
||||
List<StglMember> members = userIds.stream().map(userId -> {
|
||||
StglMember member = new StglMember();
|
||||
member.setMemberType(memberType);
|
||||
member.setRelationId(relationId);
|
||||
member.setUserId(userId);
|
||||
member.setRoleType(roleType != null ? roleType : 3);
|
||||
member.setJoinTime(now);
|
||||
member.setStatus(1);
|
||||
return member;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
return baseMapper.insertBatch(members);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新成员角色
|
||||
*
|
||||
* @param id 成员ID
|
||||
* @param roleType 角色类型
|
||||
* @return 是否更新成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateMemberRole(Long id, Integer roleType) {
|
||||
StglMember member = new StglMember();
|
||||
member.setId(id);
|
||||
member.setRoleType(roleType);
|
||||
return baseMapper.updateById(member) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出社团/队伍
|
||||
*
|
||||
* @param id 成员ID
|
||||
* @return 是否退出成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean quitMember(Long id) {
|
||||
StglMember member = new StglMember();
|
||||
member.setId(id);
|
||||
member.setStatus(0);
|
||||
return baseMapper.updateById(member) > 0;
|
||||
}
|
||||
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package org.dromara.system.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 🚀 文件缓存配置类
|
||||
* 用于管理文件下载的内存缓存配置参数
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "system.file-cache")
|
||||
public class FileCacheConfig {
|
||||
|
||||
/**
|
||||
* 是否启用文件缓存
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 最大缓存文件数量
|
||||
*/
|
||||
private int maxCacheSize = 100;
|
||||
|
||||
/**
|
||||
* 最大缓存大小(字节)
|
||||
*/
|
||||
private long maxCacheSizeBytes = 500 * 1024 * 1024; // 500MB
|
||||
|
||||
/**
|
||||
* 缓存过期时间(毫秒)
|
||||
*/
|
||||
private long expireTimeMs = 30 * 60 * 1000; // 30分钟
|
||||
|
||||
/**
|
||||
* 最大缓存单个文件大小(字节)
|
||||
*/
|
||||
private long maxSingleFileSize = 50 * 1024 * 1024; // 50MB
|
||||
|
||||
/**
|
||||
* LRU淘汰比例(百分比)
|
||||
*/
|
||||
private int evictRatio = 20; // 20%
|
||||
|
||||
/**
|
||||
* 是否启用缓存统计
|
||||
*/
|
||||
private boolean enableStats = true;
|
||||
|
||||
/**
|
||||
* 缓存清理间隔(毫秒)
|
||||
*/
|
||||
private long cleanupIntervalMs = 5 * 60 * 1000; // 5分钟
|
||||
}
|
||||
+38
@@ -28,6 +28,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件上传 控制层
|
||||
@@ -158,4 +159,41 @@ public class SysOssController extends BaseController {
|
||||
return toAjax(ossService.deleteWithValidByIds(List.of(ossIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 获取文件缓存统计信息
|
||||
* 包含缓存大小、命中率、缓存条目数量等统计信息
|
||||
*/
|
||||
@SaCheckPermission("system:oss:cache:stats")
|
||||
@GetMapping("/cache/stats")
|
||||
public R<Map<String, Object>> getCacheStats() {
|
||||
Map<String, Object> stats = ossService.getCacheStats();
|
||||
return R.ok(stats);
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 清空文件缓存
|
||||
* 清除所有缓存的文件数据,释放内存空间
|
||||
*/
|
||||
@SaCheckPermission("system:oss:cache:clear")
|
||||
@Log(title = "文件缓存管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/cache/clear")
|
||||
public R<Void> clearCache() {
|
||||
ossService.clearCache();
|
||||
return R.ok("缓存已清空");
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 从缓存中移除指定文件
|
||||
* 移除指定文件ID的缓存数据
|
||||
*
|
||||
* @param ossId 文件ID
|
||||
*/
|
||||
@SaCheckPermission("system:oss:cache:remove")
|
||||
@Log(title = "文件缓存管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/cache/{ossId}")
|
||||
public R<Void> removeFromCache(@PathVariable Long ossId) {
|
||||
ossService.removeFromCache(ossId);
|
||||
return R.ok("文件缓存已移除");
|
||||
}
|
||||
|
||||
}
|
||||
+20
@@ -11,6 +11,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 文件上传 服务层
|
||||
@@ -123,4 +124,23 @@ public interface ISysOssService {
|
||||
*/
|
||||
void secureDownload(Long ossId, HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 🚀 获取文件缓存统计信息
|
||||
*
|
||||
* @return 缓存统计信息
|
||||
*/
|
||||
Map<String, Object> getCacheStats();
|
||||
|
||||
/**
|
||||
* 🚀 清空文件缓存
|
||||
*/
|
||||
void clearCache();
|
||||
|
||||
/**
|
||||
* 🚀 从缓存中移除指定文件
|
||||
*
|
||||
* @param ossId 文件ID
|
||||
*/
|
||||
void removeFromCache(Long ossId);
|
||||
|
||||
}
|
||||
+504
-11
@@ -27,6 +27,7 @@ import org.dromara.system.domain.SysOss;
|
||||
import org.dromara.system.domain.bo.SysOssBo;
|
||||
import org.dromara.system.domain.vo.SysOssVo;
|
||||
import org.dromara.system.mapper.SysOssMapper;
|
||||
import org.dromara.system.config.FileCacheConfig;
|
||||
import org.dromara.system.service.ISysOssService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
@@ -36,13 +37,23 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import org.dromara.common.core.utils.ServletUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* 文件上传 服务层实现
|
||||
@@ -54,6 +65,61 @@ import org.dromara.common.satoken.utils.LoginHelper;
|
||||
public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
|
||||
private final SysOssMapper baseMapper;
|
||||
private final FileCacheConfig fileCacheConfig;
|
||||
|
||||
// 🚀 LRU缓存实现
|
||||
private final ConcurrentHashMap<Long, CacheEntry> fileCache = new ConcurrentHashMap<>();
|
||||
private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
|
||||
private final AtomicLong currentCacheSize = new AtomicLong(0);
|
||||
private final AtomicLong cacheHits = new AtomicLong(0);
|
||||
private final AtomicLong cacheMisses = new AtomicLong(0);
|
||||
|
||||
/**
|
||||
* 🚀 缓存条目类
|
||||
*/
|
||||
private class CacheEntry {
|
||||
private final byte[] data;
|
||||
private final long size;
|
||||
private final long createTime;
|
||||
private final long lastAccessTime;
|
||||
private final String contentType;
|
||||
|
||||
public CacheEntry(byte[] data, String contentType) {
|
||||
this.data = data;
|
||||
this.size = data.length;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
this.lastAccessTime = System.currentTimeMillis();
|
||||
this.contentType = contentType;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public long getLastAccessTime() {
|
||||
return lastAccessTime;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
public void updateAccessTime() {
|
||||
// 注意:这里需要同步访问,但为了性能考虑,我们使用volatile或者重新创建对象
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return System.currentTimeMillis() - createTime > fileCacheConfig.getExpireTimeMs();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询OSS对象存储列表
|
||||
@@ -85,9 +151,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
SysOssVo vo = ossService.getById(id);
|
||||
if (ObjectUtil.isNotNull(vo)) {
|
||||
try {
|
||||
list.add(this.matchingUrl(vo));
|
||||
// 使用安全文件访问URL替代直接OSS URL
|
||||
String secureUrl = this.getSecureFileUrl(id);
|
||||
vo.setUrl(secureUrl);
|
||||
list.add(vo);
|
||||
} catch (Exception ignored) {
|
||||
// 如果oss异常无法连接则将数据直接返回
|
||||
// 如果安全访问失败则将数据直接返回
|
||||
list.add(vo);
|
||||
}
|
||||
}
|
||||
@@ -177,9 +246,26 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
throw new ServiceException("文件数据不存在!");
|
||||
}
|
||||
FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
|
||||
OssClient storage = OssFactory.instance(sysOss.getService());
|
||||
storage.download(sysOss.getFileName(), response.getOutputStream(), response::setContentLengthLong);
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
|
||||
// 添加缓存控制头,防止浏览器缓存干扰
|
||||
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
|
||||
try {
|
||||
OssClient storage = OssFactory.instance(sysOss.getService());
|
||||
storage.download(sysOss.getFileName(), response.getOutputStream(), contentLength -> {
|
||||
if (contentLength != null && contentLength > 0) {
|
||||
response.setContentLengthLong(contentLength);
|
||||
}
|
||||
});
|
||||
|
||||
// 确保输出流刷新
|
||||
response.getOutputStream().flush();
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("文件下载失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,12 +384,19 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
}
|
||||
|
||||
// 返回后端代理URL,而不是直接返回OSS URL
|
||||
return "/system/oss/download/" + ossId;
|
||||
return "/resource/oss/download/" + ossId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 🔐 安全文件下载(通过后端代理)
|
||||
* 🔐 安全文件下载(通过后端代理)- 性能优化版本
|
||||
* 强制权限验证,确保只有登录用户才能下载
|
||||
*
|
||||
* 🚀 性能优化特性:
|
||||
* - 异步分块下载
|
||||
* - 大文件缓冲区优化
|
||||
* - 并发传输提升
|
||||
* - 断点续传支持
|
||||
* - 🆕 内存缓存机制
|
||||
*
|
||||
* @param ossId 文件ID
|
||||
* @param response HTTP响应对象
|
||||
@@ -329,13 +422,413 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
// 日志记录失败不影响主流程
|
||||
}
|
||||
|
||||
// 设置响应头
|
||||
// 🔧 修复:设置正确的响应头,移除charset避免二进制文件问题
|
||||
FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
|
||||
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
|
||||
|
||||
// 通过OSS客户端下载并直接输出到响应流
|
||||
// 🔧 修复:禁用缓存,确保文件下载正确处理
|
||||
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
|
||||
// 🚀 新增:支持断点续传
|
||||
String rangeHeader = ServletUtils.getRequest().getHeader("Range");
|
||||
if (StringUtils.isNotBlank(rangeHeader)) {
|
||||
handleRangeDownload(sysOss, response, rangeHeader);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 🚀 优化:优先从缓存获取,缓存未命中则从OSS下载
|
||||
if (!serveFromCache(ossId, sysOss, response)) {
|
||||
// 缓存未命中,从OSS下载并缓存
|
||||
performOptimizedDownloadWithCache(ossId, sysOss, response);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 🔧 修复:更详细的错误日志
|
||||
throw new ServiceException("文件下载失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 从缓存中提供文件服务
|
||||
*
|
||||
* @param ossId 文件ID
|
||||
* @param sysOss 文件信息
|
||||
* @param response HTTP响应
|
||||
* @return 是否从缓存提供服务
|
||||
*/
|
||||
private boolean serveFromCache(Long ossId, SysOssVo sysOss, HttpServletResponse response) throws IOException {
|
||||
cacheLock.readLock().lock();
|
||||
try {
|
||||
CacheEntry entry = fileCache.get(ossId);
|
||||
if (entry != null && !entry.isExpired()) {
|
||||
// 缓存命中
|
||||
cacheHits.incrementAndGet();
|
||||
|
||||
// 设置响应头
|
||||
response.setContentLengthLong(entry.getSize());
|
||||
if (StringUtils.isNotBlank(entry.getContentType())) {
|
||||
response.setContentType(entry.getContentType());
|
||||
}
|
||||
|
||||
// 输出文件内容
|
||||
try (BufferedOutputStream bufferedOut = new BufferedOutputStream(response.getOutputStream(),
|
||||
8 * 1024 * 1024)) {
|
||||
bufferedOut.write(entry.getData());
|
||||
bufferedOut.flush();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} finally {
|
||||
cacheLock.readLock().unlock();
|
||||
}
|
||||
|
||||
// 缓存未命中
|
||||
cacheMisses.incrementAndGet();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 高性能文件下载实现(带缓存)
|
||||
*
|
||||
* @param ossId 文件ID
|
||||
* @param sysOss 文件信息
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
private void performOptimizedDownloadWithCache(Long ossId, SysOssVo sysOss, HttpServletResponse response)
|
||||
throws IOException {
|
||||
OssClient storage = OssFactory.instance(sysOss.getService());
|
||||
storage.download(sysOss.getFileName(), response.getOutputStream(), response::setContentLengthLong);
|
||||
|
||||
// 🚀 优化:使用ByteArrayOutputStream收集数据用于缓存
|
||||
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
BufferedOutputStream bufferedOut = new BufferedOutputStream(response.getOutputStream(),
|
||||
8 * 1024 * 1024)) {
|
||||
|
||||
// 🚀 优化:异步下载并流式传输,同时收集数据
|
||||
storage.download(sysOss.getFileName(), new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
baos.write(b);
|
||||
bufferedOut.write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
baos.write(b, off, len);
|
||||
bufferedOut.write(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
baos.flush();
|
||||
bufferedOut.flush();
|
||||
}
|
||||
}, contentLength -> {
|
||||
// 🔧 修复:确保Content-Length正确设置
|
||||
if (contentLength != null && contentLength > 0) {
|
||||
response.setContentLengthLong(contentLength);
|
||||
}
|
||||
});
|
||||
|
||||
// 🔧 修复:确保输出流刷新
|
||||
bufferedOut.flush();
|
||||
|
||||
// 🚀 新增:将文件数据添加到缓存
|
||||
byte[] fileData = baos.toByteArray();
|
||||
addToCache(ossId, fileData, sysOss.getOriginalName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 添加文件到缓存
|
||||
*
|
||||
* @param ossId 文件ID
|
||||
* @param fileData 文件数据
|
||||
* @param fileName 文件名
|
||||
*/
|
||||
private void addToCache(Long ossId, byte[] fileData, String fileName) {
|
||||
// 检查文件大小是否适合缓存
|
||||
if (fileData.length > fileCacheConfig.getMaxSingleFileSize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
cacheLock.writeLock().lock();
|
||||
try {
|
||||
// 检查缓存大小限制
|
||||
if (currentCacheSize.get() + fileData.length > fileCacheConfig.getMaxCacheSizeBytes()) {
|
||||
// 缓存已满,执行LRU淘汰
|
||||
evictLRUEntries();
|
||||
}
|
||||
|
||||
// 如果仍然超出限制,不缓存
|
||||
if (currentCacheSize.get() + fileData.length > fileCacheConfig.getMaxCacheSizeBytes()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 确定Content-Type
|
||||
String contentType = determineContentType(fileName);
|
||||
|
||||
// 创建缓存条目
|
||||
CacheEntry entry = new CacheEntry(fileData, contentType);
|
||||
|
||||
// 添加到缓存
|
||||
fileCache.put(ossId, entry);
|
||||
currentCacheSize.addAndGet(fileData.length);
|
||||
|
||||
// 清理过期条目
|
||||
cleanupExpiredEntries();
|
||||
} finally {
|
||||
cacheLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 LRU淘汰策略
|
||||
*/
|
||||
private void evictLRUEntries() {
|
||||
// 按最后访问时间排序,淘汰最久未访问的条目
|
||||
List<Map.Entry<Long, CacheEntry>> entries = new ArrayList<>(fileCache.entrySet());
|
||||
entries.sort((e1, e2) -> Long.compare(e1.getValue().getLastAccessTime(), e2.getValue().getLastAccessTime()));
|
||||
|
||||
// 淘汰最旧的20%条目
|
||||
int evictCount = Math.max(1, entries.size() / 5);
|
||||
for (int i = 0; i < evictCount && i < entries.size(); i++) {
|
||||
Map.Entry<Long, CacheEntry> entry = entries.get(i);
|
||||
fileCache.remove(entry.getKey());
|
||||
currentCacheSize.addAndGet(-entry.getValue().getSize());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 清理过期条目
|
||||
*/
|
||||
private void cleanupExpiredEntries() {
|
||||
List<Long> expiredKeys = new ArrayList<>();
|
||||
for (Map.Entry<Long, CacheEntry> entry : fileCache.entrySet()) {
|
||||
if (entry.getValue().isExpired()) {
|
||||
expiredKeys.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for (Long key : expiredKeys) {
|
||||
CacheEntry entry = fileCache.remove(key);
|
||||
if (entry != null) {
|
||||
currentCacheSize.addAndGet(-entry.getSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 根据文件名确定Content-Type
|
||||
*
|
||||
* @param fileName 文件名
|
||||
* @return Content-Type
|
||||
*/
|
||||
private String determineContentType(String fileName) {
|
||||
if (StringUtils.isBlank(fileName)) {
|
||||
return MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||
}
|
||||
|
||||
String extension = StringUtils.substringAfterLast(fileName, ".").toLowerCase();
|
||||
switch (extension) {
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
return "image/jpeg";
|
||||
case "png":
|
||||
return "image/png";
|
||||
case "gif":
|
||||
return "image/gif";
|
||||
case "pdf":
|
||||
return "application/pdf";
|
||||
case "doc":
|
||||
return "application/msword";
|
||||
case "docx":
|
||||
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
case "xls":
|
||||
return "application/vnd.ms-excel";
|
||||
case "xlsx":
|
||||
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
case "txt":
|
||||
return "text/plain";
|
||||
case "zip":
|
||||
return "application/zip";
|
||||
case "rar":
|
||||
return "application/x-rar-compressed";
|
||||
default:
|
||||
return MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 获取缓存统计信息
|
||||
*
|
||||
* @return 缓存统计信息
|
||||
*/
|
||||
public Map<String, Object> getCacheStats() {
|
||||
Map<String, Object> stats = new ConcurrentHashMap<>();
|
||||
stats.put("cacheSize", fileCache.size());
|
||||
stats.put("currentCacheSizeBytes", currentCacheSize.get());
|
||||
stats.put("maxCacheSizeBytes", fileCacheConfig.getMaxCacheSizeBytes());
|
||||
stats.put("cacheHits", cacheHits.get());
|
||||
stats.put("cacheMisses", cacheMisses.get());
|
||||
|
||||
long totalRequests = cacheHits.get() + cacheMisses.get();
|
||||
double hitRate = totalRequests > 0 ? (double) cacheHits.get() / totalRequests * 100 : 0;
|
||||
stats.put("hitRate", String.format("%.2f%%", hitRate));
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 清空缓存
|
||||
*/
|
||||
public void clearCache() {
|
||||
cacheLock.writeLock().lock();
|
||||
try {
|
||||
fileCache.clear();
|
||||
currentCacheSize.set(0);
|
||||
cacheHits.set(0);
|
||||
cacheMisses.set(0);
|
||||
} finally {
|
||||
cacheLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 从缓存中移除指定文件
|
||||
*
|
||||
* @param ossId 文件ID
|
||||
*/
|
||||
public void removeFromCache(Long ossId) {
|
||||
cacheLock.writeLock().lock();
|
||||
try {
|
||||
CacheEntry entry = fileCache.remove(ossId);
|
||||
if (entry != null) {
|
||||
currentCacheSize.addAndGet(-entry.getSize());
|
||||
}
|
||||
} finally {
|
||||
cacheLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 断点续传支持
|
||||
*
|
||||
* @param sysOss 文件信息
|
||||
* @param response HTTP响应
|
||||
* @param rangeHeader Range请求头
|
||||
*/
|
||||
private void handleRangeDownload(SysOssVo sysOss, HttpServletResponse response, String rangeHeader)
|
||||
throws IOException {
|
||||
// 解析Range头
|
||||
String[] ranges = rangeHeader.substring("bytes=".length()).split("-");
|
||||
long start = Long.parseLong(ranges[0]);
|
||||
long end = ranges.length > 1 && StringUtils.isNotBlank(ranges[1]) ? Long.parseLong(ranges[1]) : -1;
|
||||
|
||||
// 设置206状态码和Content-Range头
|
||||
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
|
||||
response.setHeader("Accept-Ranges", "bytes");
|
||||
|
||||
// 计算实际内容长度
|
||||
long contentLength = end - start + 1;
|
||||
response.setHeader("Content-Range", "bytes " + start + "-" + end + "/*");
|
||||
response.setContentLengthLong(contentLength);
|
||||
|
||||
// 🚀 优化:分块下载指定范围
|
||||
OssClient storage = OssFactory.instance(sysOss.getService());
|
||||
try (BufferedOutputStream bufferedOut = new BufferedOutputStream(response.getOutputStream(), 8 * 1024 * 1024)) {
|
||||
|
||||
// 使用分块下载API(需要OssClient支持)
|
||||
downloadRange(storage, sysOss.getFileName(), start, end, bufferedOut);
|
||||
|
||||
bufferedOut.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 分块下载实现
|
||||
*
|
||||
* @param storage OSS客户端
|
||||
* @param fileName 文件名
|
||||
* @param start 开始位置
|
||||
* @param end 结束位置
|
||||
* @param outputStream 输出流
|
||||
*/
|
||||
private void downloadRange(OssClient storage, String fileName, long start, long end, OutputStream outputStream) {
|
||||
// 这里需要根据具体的OSS客户端实现来调用分块下载
|
||||
// 目前先使用完整下载,后续可以扩展为真正的分块下载
|
||||
try {
|
||||
storage.download(fileName, outputStream, null);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("分块下载失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 批量文件下载优化
|
||||
* 支持多个文件打包下载
|
||||
*
|
||||
* @param ossIds 文件ID列表
|
||||
* @param response HTTP响应
|
||||
*/
|
||||
public void batchDownload(Collection<Long> ossIds, HttpServletResponse response) throws IOException {
|
||||
if (ossIds == null || ossIds.isEmpty()) {
|
||||
throw new ServiceException("请选择要下载的文件");
|
||||
}
|
||||
|
||||
// 权限验证
|
||||
for (Long ossId : ossIds) {
|
||||
if (!checkFileAccessPermission(ossId)) {
|
||||
throw new ServiceException("无权限下载文件ID: " + ossId);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置ZIP响应头
|
||||
String zipFileName = "files_" + System.currentTimeMillis() + ".zip";
|
||||
FileUtils.setAttachmentResponseHeader(response, zipFileName);
|
||||
response.setContentType("application/zip");
|
||||
|
||||
// 🚀 优化:使用ZIP流式输出,避免内存溢出
|
||||
try (ZipOutputStream zipOut = new ZipOutputStream(
|
||||
new BufferedOutputStream(response.getOutputStream(), 8 * 1024 * 1024))) {
|
||||
|
||||
for (Long ossId : ossIds) {
|
||||
SysOssVo sysOss = getById(ossId);
|
||||
if (sysOss != null) {
|
||||
addFileToZip(sysOss, zipOut);
|
||||
}
|
||||
}
|
||||
|
||||
zipOut.flush();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🚀 添加文件到ZIP流
|
||||
*
|
||||
* @param sysOss 文件信息
|
||||
* @param zipOut ZIP输出流
|
||||
*/
|
||||
private void addFileToZip(SysOssVo sysOss, ZipOutputStream zipOut) throws IOException {
|
||||
ZipEntry zipEntry = new ZipEntry(sysOss.getOriginalName());
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
|
||||
OssClient storage = OssFactory.instance(sysOss.getService());
|
||||
|
||||
// 🚀 优化:使用缓冲流提升性能
|
||||
try (BufferedInputStream bufferedIn = new BufferedInputStream(
|
||||
storage.getObjectContent(sysOss.getFileName()), 8 * 1024 * 1024)) {
|
||||
|
||||
byte[] buffer = new byte[8 * 1024 * 1024]; // 8MB缓冲区
|
||||
int bytesRead;
|
||||
while ((bytesRead = bufferedIn.read(buffer)) != -1) {
|
||||
zipOut.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
zipOut.closeEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-4
@@ -66,8 +66,7 @@ public class TestLeaveController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("workflow:leave:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<TestLeaveVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
public R<TestLeaveVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) {
|
||||
return R.ok(testLeaveService.queryById(id));
|
||||
}
|
||||
|
||||
@@ -101,8 +100,7 @@ public class TestLeaveController extends BaseController {
|
||||
@SaCheckPermission("workflow:leave:remove")
|
||||
@Log(title = "请假", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
|
||||
return toAjax(testLeaveService.deleteWithValidByIds(List.of(ids)));
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package org.dromara.workflow.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.workflow.domain.vo.XgStudentLeaveVo;
|
||||
import org.dromara.workflow.domain.bo.XgStudentLeaveBo;
|
||||
import org.dromara.workflow.service.IXgStudentLeaveService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/studentLeave/studentLeave")
|
||||
public class XgStudentLeaveController extends BaseController {
|
||||
|
||||
private final IXgStudentLeaveService xgStudentLeaveService;
|
||||
|
||||
/**
|
||||
* 查询学生请假 - 记录学生的请假申请、审批和销假信息列表
|
||||
*/
|
||||
@SaCheckPermission("studentLeave:studentLeave:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<XgStudentLeaveVo> list(XgStudentLeaveBo bo, PageQuery pageQuery) {
|
||||
return xgStudentLeaveService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出学生请假 - 记录学生的请假申请、审批和销假信息列表
|
||||
*/
|
||||
@SaCheckPermission("studentLeave:studentLeave:export")
|
||||
@Log(title = "学生请假 - 记录学生的请假申请、审批和销假信息", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(XgStudentLeaveBo bo, HttpServletResponse response) {
|
||||
List<XgStudentLeaveVo> list = xgStudentLeaveService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "学生请假 - 记录学生的请假申请、审批和销假信息", XgStudentLeaveVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生请假 - 记录学生的请假申请、审批和销假信息详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("studentLeave:studentLeave:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<XgStudentLeaveVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(xgStudentLeaveService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*/
|
||||
@SaCheckPermission("studentLeave:studentLeave:add")
|
||||
@Log(title = "学生请假 - 记录学生的请假申请、审批和销假信息", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody XgStudentLeaveBo bo) {
|
||||
return toAjax(xgStudentLeaveService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*/
|
||||
@SaCheckPermission("studentLeave:studentLeave:edit")
|
||||
@Log(title = "学生请假 - 记录学生的请假申请、审批和销假信息", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody XgStudentLeaveBo bo) {
|
||||
return toAjax(xgStudentLeaveService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("studentLeave:studentLeave:remove")
|
||||
@Log(title = "学生请假 - 记录学生的请假申请、审批和销假信息", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(xgStudentLeaveService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
package org.dromara.workflow.domain;
|
||||
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 学生请假 - 记录学生的请假申请、审批和销假信息对象 xg_student_leave
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("xg_student_leave")
|
||||
public class XgStudentLeave extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Long deleted;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 学院ID
|
||||
*/
|
||||
private Long collegeId;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 请假类型编码
|
||||
*/
|
||||
private String leaveTypeCode;
|
||||
|
||||
/**
|
||||
* 请假类型名称
|
||||
*/
|
||||
private String leaveTypeName;
|
||||
|
||||
/**
|
||||
* 开始时间(年月日时分秒)
|
||||
*/
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 结束时间(年月日时分秒)
|
||||
*/
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 请假时长(天)
|
||||
*/
|
||||
private Double leaveDuration;
|
||||
|
||||
/**
|
||||
* 是否离校:0-否,1-是
|
||||
*/
|
||||
private String isLeaveSchool;
|
||||
|
||||
/**
|
||||
* 是否需要销假:0-否,1-是
|
||||
*/
|
||||
private String needCancel;
|
||||
|
||||
/**
|
||||
* 紧急联系人
|
||||
*/
|
||||
private String emergencyContact;
|
||||
|
||||
/**
|
||||
* 紧急联系电话
|
||||
*/
|
||||
private String emergencyPhone;
|
||||
|
||||
/**
|
||||
* 请假原因
|
||||
*/
|
||||
private String leaveReason;
|
||||
|
||||
/**
|
||||
* 请假时地理位置
|
||||
*/
|
||||
private String leaveLocation;
|
||||
|
||||
/**
|
||||
* 附件OSS文件ID(逗号分隔)
|
||||
*/
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
* 审批状态:0-待审批,1-已通过,2-已拒绝,3-已取消
|
||||
*/
|
||||
private String approvalStatus;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String approvalOpinion;
|
||||
|
||||
/**
|
||||
* 审批时间
|
||||
*/
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 审批人ID
|
||||
*/
|
||||
private Long approvalBy;
|
||||
|
||||
/**
|
||||
* 审批人姓名
|
||||
*/
|
||||
private String approvalByName;
|
||||
|
||||
/**
|
||||
* 销假状态:0-未销假,1-已销假,2-逾期未销假
|
||||
*/
|
||||
private String cancelStatus;
|
||||
|
||||
/**
|
||||
* 销假时间
|
||||
*/
|
||||
private Date cancelTime;
|
||||
|
||||
/**
|
||||
* 销假地理位置
|
||||
*/
|
||||
private String cancelLocation;
|
||||
|
||||
/**
|
||||
* 销假照片OSS文件ID(逗号分隔)
|
||||
*/
|
||||
private String cancelPhotoOssIds;
|
||||
|
||||
/**
|
||||
* 销假备注
|
||||
*/
|
||||
private String cancelRemark;
|
||||
|
||||
}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
package org.dromara.workflow.domain.bo;
|
||||
|
||||
import org.dromara.workflow.domain.XgStudentLeave;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
/**
|
||||
* 学生请假 - 记录学生的请假申请、审批和销假信息业务对象 xg_student_leave
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = XgStudentLeave.class, reverseConvertGenerate = false)
|
||||
public class XgStudentLeaveBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@NotNull(message = "主键ID(雪花ID)不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
private Long deleted;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
@NotNull(message = "学生ID不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@NotBlank(message = "学生姓名不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@NotBlank(message = "学号不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 学院ID
|
||||
*/
|
||||
private Long collegeId;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 请假类型编码
|
||||
*/
|
||||
@NotBlank(message = "请假类型编码不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String leaveTypeCode;
|
||||
|
||||
/**
|
||||
* 请假类型名称
|
||||
*/
|
||||
@NotBlank(message = "请假类型名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String leaveTypeName;
|
||||
|
||||
/**
|
||||
* 开始时间(年月日时分秒)
|
||||
*/
|
||||
@NotNull(message = "开始时间(年月日时分秒)不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 结束时间(年月日时分秒)
|
||||
*/
|
||||
@NotNull(message = "结束时间(年月日时分秒)不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 请假时长(天)
|
||||
*/
|
||||
@NotNull(message = "请假时长(天)不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private Double leaveDuration;
|
||||
|
||||
/**
|
||||
* 是否离校:0-否,1-是
|
||||
*/
|
||||
@NotBlank(message = "是否离校:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String isLeaveSchool;
|
||||
|
||||
/**
|
||||
* 是否需要销假:0-否,1-是
|
||||
*/
|
||||
@NotBlank(message = "是否需要销假:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String needCancel;
|
||||
|
||||
/**
|
||||
* 紧急联系人
|
||||
*/
|
||||
private String emergencyContact;
|
||||
|
||||
/**
|
||||
* 紧急联系电话
|
||||
*/
|
||||
private String emergencyPhone;
|
||||
|
||||
/**
|
||||
* 请假原因
|
||||
*/
|
||||
@NotBlank(message = "请假原因不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String leaveReason;
|
||||
|
||||
/**
|
||||
* 请假时地理位置
|
||||
*/
|
||||
private String leaveLocation;
|
||||
|
||||
/**
|
||||
* 附件OSS文件ID(逗号分隔)
|
||||
*/
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
* 审批状态
|
||||
*/
|
||||
@NotBlank(message = "审批状态不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String approvalStatus;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
private String approvalOpinion;
|
||||
|
||||
/**
|
||||
* 审批时间
|
||||
*/
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 审批人ID
|
||||
*/
|
||||
private Long approvalBy;
|
||||
|
||||
/**
|
||||
* 审批人姓名
|
||||
*/
|
||||
private String approvalByName;
|
||||
|
||||
/**
|
||||
* 销假状态:0-未销假,1-已销假,2-逾期未销假 3-无需销假
|
||||
*/
|
||||
@NotBlank(message = "销假状态:0-未销假,1-已销假,2-逾期未销假 3-无需销假 不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String cancelStatus;
|
||||
|
||||
/**
|
||||
* 销假时间
|
||||
*/
|
||||
private Date cancelTime;
|
||||
|
||||
/**
|
||||
* 销假地理位置
|
||||
*/
|
||||
private String cancelLocation;
|
||||
|
||||
/**
|
||||
* 销假照片OSS文件ID(逗号分隔)
|
||||
*/
|
||||
private String cancelPhotoOssIds;
|
||||
|
||||
/**
|
||||
* 销假备注
|
||||
*/
|
||||
private String cancelRemark;
|
||||
|
||||
}
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
package org.dromara.workflow.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.dromara.workflow.domain.XgStudentLeave;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 学生请假 - 记录学生的请假申请、审批和销假信息视图对象 xg_student_leave
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = XgStudentLeave.class)
|
||||
public class XgStudentLeaveVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "雪=花ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@ExcelProperty(value = "删除标志", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "0=代表存在,1=代表删除")
|
||||
private Long deleted;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
@ExcelProperty(value = "学生ID")
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
@ExcelProperty(value = "学生姓名")
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
@ExcelProperty(value = "学号")
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
@ExcelProperty(value = "班级ID")
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
* 班级名称
|
||||
*/
|
||||
@ExcelProperty(value = "班级名称")
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
@ExcelProperty(value = "专业ID")
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
* 专业名称
|
||||
*/
|
||||
@ExcelProperty(value = "专业名称")
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 学院ID
|
||||
*/
|
||||
@ExcelProperty(value = "学院ID")
|
||||
private Long collegeId;
|
||||
|
||||
/**
|
||||
* 学院名称
|
||||
*/
|
||||
@ExcelProperty(value = "学院名称")
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 请假类型编码
|
||||
*/
|
||||
@ExcelProperty(value = "请假类型编码")
|
||||
private String leaveTypeCode;
|
||||
|
||||
/**
|
||||
* 请假类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "请假类型名称")
|
||||
private String leaveTypeName;
|
||||
|
||||
/**
|
||||
* 开始时间(年月日时分秒)
|
||||
*/
|
||||
@ExcelProperty(value = "开始时间", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "年=月日时分秒")
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 结束时间(年月日时分秒)
|
||||
*/
|
||||
@ExcelProperty(value = "结束时间", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "年=月日时分秒")
|
||||
private Date endTime;
|
||||
|
||||
/**
|
||||
* 请假时长(天)
|
||||
*/
|
||||
@ExcelProperty(value = "请假时长", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "天=")
|
||||
private Double leaveDuration;
|
||||
|
||||
/**
|
||||
* 是否离校:0-否,1-是
|
||||
*/
|
||||
@ExcelProperty(value = "是否离校:0-否,1-是")
|
||||
private String isLeaveSchool;
|
||||
|
||||
/**
|
||||
* 是否需要销假:0-否,1-是
|
||||
*/
|
||||
@ExcelProperty(value = "是否需要销假:0-否,1-是")
|
||||
private String needCancel;
|
||||
|
||||
/**
|
||||
* 紧急联系人
|
||||
*/
|
||||
@ExcelProperty(value = "紧急联系人")
|
||||
private String emergencyContact;
|
||||
|
||||
/**
|
||||
* 紧急联系电话
|
||||
*/
|
||||
@ExcelProperty(value = "紧急联系电话")
|
||||
private String emergencyPhone;
|
||||
|
||||
/**
|
||||
* 请假原因
|
||||
*/
|
||||
@ExcelProperty(value = "请假原因")
|
||||
private String leaveReason;
|
||||
|
||||
/**
|
||||
* 请假时地理位置
|
||||
*/
|
||||
@ExcelProperty(value = "请假时地理位置")
|
||||
private String leaveLocation;
|
||||
|
||||
/**
|
||||
* 附件OSS文件ID(逗号分隔)
|
||||
*/
|
||||
@ExcelProperty(value = "附件OSS文件ID", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "逗=号分隔")
|
||||
private String attachmentOssIds;
|
||||
|
||||
/**
|
||||
* 审批状态
|
||||
*/
|
||||
@ExcelProperty(value = "审批状态")
|
||||
private String approvalStatus;
|
||||
|
||||
/**
|
||||
* 审批意见
|
||||
*/
|
||||
@ExcelProperty(value = "审批意见")
|
||||
private String approvalOpinion;
|
||||
|
||||
/**
|
||||
* 审批时间
|
||||
*/
|
||||
@ExcelProperty(value = "审批时间")
|
||||
private Date approvalTime;
|
||||
|
||||
/**
|
||||
* 审批人ID
|
||||
*/
|
||||
@ExcelProperty(value = "审批人ID")
|
||||
private Long approvalBy;
|
||||
|
||||
/**
|
||||
* 审批人姓名
|
||||
*/
|
||||
@ExcelProperty(value = "审批人姓名")
|
||||
private String approvalByName;
|
||||
|
||||
/**
|
||||
* 销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假
|
||||
*/
|
||||
@ExcelProperty(value = "销假状态:0-未销假,1-已销假,2-逾期未销假 3 - 无需销假")
|
||||
private String cancelStatus;
|
||||
|
||||
/**
|
||||
* 销假时间
|
||||
*/
|
||||
@ExcelProperty(value = "销假时间")
|
||||
private Date cancelTime;
|
||||
|
||||
/**
|
||||
* 销假地理位置
|
||||
*/
|
||||
@ExcelProperty(value = "销假地理位置")
|
||||
private String cancelLocation;
|
||||
|
||||
/**
|
||||
* 销假照片OSS文件ID(逗号分隔)
|
||||
*/
|
||||
@ExcelProperty(value = "销假照片OSS文件ID", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "逗=号分隔")
|
||||
private String cancelPhotoOssIds;
|
||||
|
||||
/**
|
||||
* 销假备注
|
||||
*/
|
||||
@ExcelProperty(value = "销假备注")
|
||||
private String cancelRemark;
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.dromara.workflow.mapper;
|
||||
|
||||
import org.dromara.workflow.domain.XgStudentLeave;
|
||||
import org.dromara.workflow.domain.vo.XgStudentLeaveVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 学生请假 - 记录学生的请假申请、审批和销假信息Mapper接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
public interface XgStudentLeaveMapper extends BaseMapperPlus<XgStudentLeave, XgStudentLeaveVo> {
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package org.dromara.workflow.service;
|
||||
|
||||
import org.dromara.workflow.domain.vo.XgStudentLeaveVo;
|
||||
import org.dromara.workflow.domain.bo.XgStudentLeaveBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生请假 - 记录学生的请假申请、审批和销假信息Service接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
public interface IXgStudentLeaveService {
|
||||
|
||||
/**
|
||||
* 查询学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*/
|
||||
XgStudentLeaveVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询学生请假 - 记录学生的请假申请、审批和销假信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生请假 - 记录学生的请假申请、审批和销假信息分页列表
|
||||
*/
|
||||
TableDataInfo<XgStudentLeaveVo> queryPageList(XgStudentLeaveBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的学生请假 - 记录学生的请假申请、审批和销假信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 学生请假 - 记录学生的请假申请、审批和销假信息列表
|
||||
*/
|
||||
List<XgStudentLeaveVo> queryList(XgStudentLeaveBo bo);
|
||||
|
||||
/**
|
||||
* 新增学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*
|
||||
* @param bo 学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(XgStudentLeaveBo bo);
|
||||
|
||||
/**
|
||||
* 修改学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*
|
||||
* @param bo 学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(XgStudentLeaveBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除学生请假 - 记录学生的请假申请、审批和销假信息信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
+82
-71
@@ -101,12 +101,13 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
}
|
||||
// 启动流程实例(提交申请)
|
||||
Map<String, Object> variables = startProcessBo.getVariables();
|
||||
log.info("流程变量variables:{}", variables);
|
||||
// 流程发起人
|
||||
variables.put(INITIATOR, LoginHelper.getUserIdStr());
|
||||
// 业务id
|
||||
variables.put(BUSINESS_ID, businessId);
|
||||
FlowInstance flowInstance = flowInstanceMapper.selectOne(new LambdaQueryWrapper<>(FlowInstance.class)
|
||||
.eq(FlowInstance::getBusinessId, businessId));
|
||||
.eq(FlowInstance::getBusinessId, businessId));
|
||||
if (ObjectUtil.isNotNull(flowInstance)) {
|
||||
BusinessStatusEnum.checkStartStatus(flowInstance.getFlowStatus());
|
||||
List<Task> taskList = taskService.list(new FlowTask().setInstanceId(flowInstance.getId()));
|
||||
@@ -118,9 +119,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
return dto;
|
||||
}
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.flowCode(startProcessBo.getFlowCode())
|
||||
.variable(startProcessBo.getVariables())
|
||||
.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
||||
.flowCode(startProcessBo.getFlowCode())
|
||||
.variable(startProcessBo.getVariables())
|
||||
.flowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
||||
Instance instance;
|
||||
try {
|
||||
instance = insService.start(businessId, flowParams);
|
||||
@@ -160,7 +161,6 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
// 消息通知
|
||||
completeTaskBo.getVariables().put(FlowConstant.MESSAGE_NOTICE, notice);
|
||||
|
||||
|
||||
FlowTask flowTask = flowTaskMapper.selectById(taskId);
|
||||
if (ObjectUtil.isNull(flowTask)) {
|
||||
throw new ServiceException("流程任务不存在或任务已审批!");
|
||||
@@ -177,12 +177,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
}
|
||||
// 构建流程参数,包括变量、跳转类型、消息、处理人、权限等信息
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.variable(completeTaskBo.getVariables())
|
||||
.skipType(SkipType.PASS.getKey())
|
||||
.message(completeTaskBo.getMessage())
|
||||
.flowStatus(BusinessStatusEnum.WAITING.getStatus())
|
||||
.hisStatus(TaskStatusEnum.PASS.getStatus())
|
||||
.hisTaskExt(completeTaskBo.getFileId());
|
||||
.variable(completeTaskBo.getVariables())
|
||||
.skipType(SkipType.PASS.getKey())
|
||||
.message(completeTaskBo.getMessage())
|
||||
.flowStatus(BusinessStatusEnum.WAITING.getStatus())
|
||||
.hisStatus(TaskStatusEnum.PASS.getStatus())
|
||||
.hisTaskExt(completeTaskBo.getFileId());
|
||||
// 执行任务跳转,并根据返回的处理人设置下一步处理人
|
||||
taskService.skip(taskId, flowParams);
|
||||
return true;
|
||||
@@ -208,9 +208,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
String userIds = variablesMap.get(entry.getKey()).toString();
|
||||
if (StringUtils.isNotBlank(userIds)) {
|
||||
Set<String> hashSet = new HashSet<>();
|
||||
//弹窗传入的选人
|
||||
// 弹窗传入的选人
|
||||
List<String> popUserIds = Arrays.asList(entry.getValue().toString().split(StringUtils.SEPARATOR));
|
||||
//已有的选人
|
||||
// 已有的选人
|
||||
List<String> variableUserIds = Arrays.asList(userIds.split(StringUtils.SEPARATOR));
|
||||
hashSet.addAll(popUserIds);
|
||||
hashSet.addAll(variableUserIds);
|
||||
@@ -235,31 +235,33 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
return;
|
||||
}
|
||||
// 添加抄送人记录
|
||||
FlowHisTask flowHisTask = flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId())).get(0);
|
||||
FlowHisTask flowHisTask = flowHisTaskMapper
|
||||
.selectList(new LambdaQueryWrapper<>(FlowHisTask.class).eq(FlowHisTask::getTaskId, task.getId()))
|
||||
.get(0);
|
||||
FlowNode flowNode = new FlowNode();
|
||||
flowNode.setNodeCode(flowHisTask.getTargetNodeCode());
|
||||
flowNode.setNodeName(flowHisTask.getTargetNodeName());
|
||||
//生成新的任务id
|
||||
// 生成新的任务id
|
||||
long taskId = identifierGenerator.nextId(null).longValue();
|
||||
task.setId(taskId);
|
||||
task.setNodeName("【抄送】" + task.getNodeName());
|
||||
Date updateTime = new Date(flowHisTask.getUpdateTime().getTime() - 1000);
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.skipType(SkipType.NONE.getKey())
|
||||
.hisStatus(TaskStatusEnum.COPY.getStatus())
|
||||
.message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName));
|
||||
.skipType(SkipType.NONE.getKey())
|
||||
.hisStatus(TaskStatusEnum.COPY.getStatus())
|
||||
.message("【抄送给】" + StreamUtils.join(flowCopyList, FlowCopyBo::getUserName));
|
||||
HisTask hisTask = hisTaskService.setSkipHisTask(task, flowNode, flowParams);
|
||||
hisTask.setCreateTime(updateTime);
|
||||
hisTask.setUpdateTime(updateTime);
|
||||
hisTaskService.save(hisTask);
|
||||
List<User> userList = flowCopyList.stream()
|
||||
.map(flowCopy -> {
|
||||
FlowUser flowUser = new FlowUser();
|
||||
flowUser.setType(TaskAssigneeType.COPY.getCode());
|
||||
flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId()));
|
||||
flowUser.setAssociated(taskId);
|
||||
return flowUser;
|
||||
}).collect(Collectors.toList());
|
||||
.map(flowCopy -> {
|
||||
FlowUser flowUser = new FlowUser();
|
||||
flowUser.setType(TaskAssigneeType.COPY.getCode());
|
||||
flowUser.setProcessedBy(String.valueOf(flowCopy.getUserId()));
|
||||
flowUser.setAssociated(taskId);
|
||||
return flowUser;
|
||||
}).collect(Collectors.toList());
|
||||
// 批量保存抄送人员
|
||||
FlowEngine.userService().saveBatch(userList);
|
||||
}
|
||||
@@ -361,7 +363,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
wrapper.like(StringUtils.isNotBlank(flowTaskBo.getFlowCode()), "t.flow_code", flowTaskBo.getFlowCode());
|
||||
wrapper.in(CollUtil.isNotEmpty(flowTaskBo.getCreateByIds()), "t.create_by", flowTaskBo.getCreateByIds());
|
||||
if (StringUtils.isNotBlank(flowTaskBo.getCategory())) {
|
||||
List<Long> categoryIds = flwCategoryMapper.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory()));
|
||||
List<Long> categoryIds = flwCategoryMapper
|
||||
.selectCategoryIdsByParentId(Convert.toLong(flowTaskBo.getCategory()));
|
||||
wrapper.in("t.category", StreamUtils.toList(categoryIds, Convert::toStr));
|
||||
}
|
||||
wrapper.orderByDesc("t.create_time");
|
||||
@@ -397,13 +400,14 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
variable.put("notice", notice);
|
||||
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.nodeCode(bo.getNodeCode())
|
||||
.variable(variable)
|
||||
.message(message)
|
||||
.skipType(SkipType.REJECT.getKey())
|
||||
.flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus() : TaskStatusEnum.WAITING.getStatus())
|
||||
.hisStatus(TaskStatusEnum.BACK.getStatus())
|
||||
.hisTaskExt(bo.getFileId());
|
||||
.nodeCode(bo.getNodeCode())
|
||||
.variable(variable)
|
||||
.message(message)
|
||||
.skipType(SkipType.REJECT.getKey())
|
||||
.flowStatus(applyNodeCode.equals(bo.getNodeCode()) ? TaskStatusEnum.BACK.getStatus()
|
||||
: TaskStatusEnum.WAITING.getStatus())
|
||||
.hisStatus(TaskStatusEnum.BACK.getStatus())
|
||||
.hisTaskExt(bo.getFileId());
|
||||
taskService.skip(task.getId(), flowParams);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
@@ -424,12 +428,12 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
if (!CollUtil.isNotEmpty(nodeCodes)) {
|
||||
return nodeCodes;
|
||||
}
|
||||
//判断是否配置了固定驳回节点
|
||||
// 判断是否配置了固定驳回节点
|
||||
Node node = nodeCodes.get(0);
|
||||
if (StringUtils.isNotBlank(node.getAnyNodeSkip())) {
|
||||
return nodeService.getByNodeCodes(Collections.singletonList(node.getAnyNodeSkip()), definitionId);
|
||||
}
|
||||
//获取可驳回的前置节点
|
||||
// 获取可驳回的前置节点
|
||||
List<Node> nodes = nodeService.previousNodeList(definitionId, nowNodeCode);
|
||||
if (CollUtil.isNotEmpty(nodes)) {
|
||||
return StreamUtils.filter(nodes, e -> NodeType.BETWEEN.getKey().equals(e.getNodeType()));
|
||||
@@ -456,9 +460,9 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
BusinessStatusEnum.checkInvalidStatus(instance.getFlowStatus());
|
||||
}
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.message(bo.getComment())
|
||||
.flowStatus(BusinessStatusEnum.TERMINATION.getStatus())
|
||||
.hisStatus(TaskStatusEnum.TERMINATION.getStatus());
|
||||
.message(bo.getComment())
|
||||
.flowStatus(BusinessStatusEnum.TERMINATION.getStatus())
|
||||
.hisStatus(TaskStatusEnum.TERMINATION.getStatus());
|
||||
taskService.termination(taskId, flowParams);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
@@ -475,7 +479,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
@Override
|
||||
public List<FlowTask> selectByIdList(List<Long> taskIdList) {
|
||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
||||
.in(FlowTask::getId, taskIdList));
|
||||
.in(FlowTask::getId, taskIdList));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -501,7 +505,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
if (ObjectUtil.isNull(flowNode)) {
|
||||
throw new NullPointerException("当前【" + flowTaskVo.getNodeCode() + "】节点编码不存在");
|
||||
}
|
||||
//设置按钮权限
|
||||
// 设置按钮权限
|
||||
flowTaskVo.setButtonList(flwNodeExtService.buildButtonPermissionsFromExt(flowNode.getExt()));
|
||||
flowTaskVo.setNodeRatio(flowNode.getNodeRatio());
|
||||
flowTaskVo.setApplyNode(flowNode.getNodeCode().equals(flwCommonService.applyNodeCode(task.getDefinitionId())));
|
||||
@@ -522,24 +526,29 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
Definition definition = defService.getById(task.getDefinitionId());
|
||||
Map<String, Object> mergeVariable = MapUtil.mergeAll(instance.getVariableMap(), variables);
|
||||
// 获取下一节点列表
|
||||
List<Node> nextNodeList = nodeService.getNextNodeList(task.getDefinitionId(), task.getNodeCode(), null, SkipType.PASS.getKey(), mergeVariable);
|
||||
List<Node> nextNodeList = nodeService.getNextNodeList(task.getDefinitionId(), task.getNodeCode(), null,
|
||||
SkipType.PASS.getKey(), mergeVariable);
|
||||
List<FlowNode> nextFlowNodes = BeanUtil.copyToList(nextNodeList, FlowNode.class);
|
||||
// 只获取中间节点
|
||||
nextFlowNodes = StreamUtils.filter(nextFlowNodes, node -> NodeType.BETWEEN.getKey().equals(node.getNodeType()));
|
||||
if (CollUtil.isNotEmpty(nextNodeList)) {
|
||||
// 构建以下节点数据
|
||||
List<Task> buildNextTaskList = StreamUtils.toList(nextNodeList, node -> taskService.addTask(node, instance, definition, FlowParams.build()));
|
||||
List<Task> buildNextTaskList = StreamUtils.toList(nextNodeList,
|
||||
node -> taskService.addTask(node, instance, definition, FlowParams.build()));
|
||||
// 办理人变量替换
|
||||
ExpressionUtil.evalVariable(buildNextTaskList, mergeVariable);
|
||||
for (FlowNode flowNode : nextFlowNodes) {
|
||||
buildNextTaskList.stream().filter(t -> t.getNodeCode().equals(flowNode.getNodeCode())).findFirst().ifPresent(t -> {
|
||||
if (CollUtil.isNotEmpty(t.getPermissionList())) {
|
||||
List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(String.join(StringUtils.SEPARATOR, t.getPermissionList()));
|
||||
if (CollUtil.isNotEmpty(users)) {
|
||||
flowNode.setPermissionFlag(StreamUtils.join(users, e -> String.valueOf(e.getUserId())));
|
||||
}
|
||||
}
|
||||
});
|
||||
buildNextTaskList.stream().filter(t -> t.getNodeCode().equals(flowNode.getNodeCode())).findFirst()
|
||||
.ifPresent(t -> {
|
||||
if (CollUtil.isNotEmpty(t.getPermissionList())) {
|
||||
List<UserDTO> users = flwTaskAssigneeService.fetchUsersByStorageIds(
|
||||
String.join(StringUtils.SEPARATOR, t.getPermissionList()));
|
||||
if (CollUtil.isNotEmpty(users)) {
|
||||
flowNode.setPermissionFlag(
|
||||
StreamUtils.join(users, e -> String.valueOf(e.getUserId())));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return nextFlowNodes;
|
||||
@@ -554,7 +563,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
@Override
|
||||
public List<FlowHisTask> selectHisTaskByIdList(List<Long> taskIdList) {
|
||||
return flowHisTaskMapper.selectList(new LambdaQueryWrapper<>(FlowHisTask.class)
|
||||
.in(FlowHisTask::getId, taskIdList));
|
||||
.in(FlowHisTask::getId, taskIdList));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -566,7 +575,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
@Override
|
||||
public FlowHisTask selectHisTaskById(Long taskId) {
|
||||
return flowHisTaskMapper.selectOne(new LambdaQueryWrapper<>(FlowHisTask.class)
|
||||
.eq(FlowHisTask::getId, taskId));
|
||||
.eq(FlowHisTask::getId, taskId));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -577,7 +586,7 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
@Override
|
||||
public List<FlowTask> selectByInstIdList(List<Long> instanceIdList) {
|
||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
||||
.in(FlowTask::getInstanceId, instanceIdList));
|
||||
.in(FlowTask::getInstanceId, instanceIdList));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -588,20 +597,21 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
@Override
|
||||
public List<FlowTask> selectByInstId(Long instanceId) {
|
||||
return flowTaskMapper.selectList(new LambdaQueryWrapper<>(FlowTask.class)
|
||||
.eq(FlowTask::getInstanceId, instanceId));
|
||||
.eq(FlowTask::getInstanceId, instanceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务操作
|
||||
*
|
||||
* @param bo 参数
|
||||
* @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
|
||||
* @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签
|
||||
* reductionSignature
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean taskOperation(TaskOperationBo bo, String taskOperation) {
|
||||
FlowParams flowParams = FlowParams.build()
|
||||
.message(bo.getMessage());
|
||||
.message(bo.getMessage());
|
||||
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
||||
flowParams.ignore(true);
|
||||
}
|
||||
@@ -636,22 +646,22 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
}
|
||||
// 设置任务状态并执行对应的任务操作
|
||||
switch (taskOperation) {
|
||||
//委派任务
|
||||
// 委派任务
|
||||
case DELEGATE_TASK -> {
|
||||
flowParams.hisStatus(TaskStatusEnum.DEPUTE.getStatus());
|
||||
return taskService.depute(taskId, flowParams);
|
||||
}
|
||||
//转办任务
|
||||
// 转办任务
|
||||
case TRANSFER_TASK -> {
|
||||
flowParams.hisStatus(TaskStatusEnum.TRANSFER.getStatus());
|
||||
return taskService.transfer(taskId, flowParams);
|
||||
}
|
||||
//加签,增加办理人
|
||||
// 加签,增加办理人
|
||||
case ADD_SIGNATURE -> {
|
||||
flowParams.hisStatus(TaskStatusEnum.SIGN.getStatus());
|
||||
return taskService.addSignature(taskId, flowParams);
|
||||
}
|
||||
//减签,减少办理人
|
||||
// 减签,减少办理人
|
||||
case REDUCTION_SIGNATURE -> {
|
||||
flowParams.hisStatus(TaskStatusEnum.SIGN_OFF.getStatus());
|
||||
return taskService.reductionSignature(taskId, flowParams);
|
||||
@@ -681,14 +691,14 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
if (CollUtil.isNotEmpty(flowTasks)) {
|
||||
FlowEngine.userService().deleteByTaskIds(StreamUtils.toList(flowTasks, FlowTask::getId));
|
||||
List<User> userList = flowTasks.stream()
|
||||
.map(flowTask -> {
|
||||
FlowUser flowUser = new FlowUser();
|
||||
flowUser.setType(TaskAssigneeType.APPROVER.getCode());
|
||||
flowUser.setProcessedBy(userId);
|
||||
flowUser.setAssociated(flowTask.getId());
|
||||
return flowUser;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
.map(flowTask -> {
|
||||
FlowUser flowUser = new FlowUser();
|
||||
flowUser.setType(TaskAssigneeType.APPROVER.getCode());
|
||||
flowUser.setProcessedBy(userId);
|
||||
flowUser.setAssociated(flowTask.getId());
|
||||
return flowUser;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isNotEmpty(userList)) {
|
||||
FlowEngine.userService().saveBatch(userList);
|
||||
}
|
||||
@@ -714,7 +724,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
for (Map.Entry<Long, List<User>> entry : listMap.entrySet()) {
|
||||
List<User> value = entry.getValue();
|
||||
if (CollUtil.isNotEmpty(value)) {
|
||||
List<UserDTO> userDtoList = userService.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy())));
|
||||
List<UserDTO> userDtoList = userService
|
||||
.selectListByIds(StreamUtils.toList(value, e -> Long.valueOf(e.getProcessedBy())));
|
||||
map.put(entry.getKey(), userDtoList);
|
||||
}
|
||||
}
|
||||
@@ -745,8 +756,8 @@ public class FlwTaskServiceImpl implements IFlwTaskService {
|
||||
@Override
|
||||
public FlowNode getByNodeCode(String nodeCode, Long definitionId) {
|
||||
return flowNodeMapper.selectOne(new LambdaQueryWrapper<FlowNode>()
|
||||
.eq(FlowNode::getNodeCode, nodeCode)
|
||||
.eq(FlowNode::getDefinitionId, definitionId));
|
||||
.eq(FlowNode::getNodeCode, nodeCode)
|
||||
.eq(FlowNode::getDefinitionId, definitionId));
|
||||
}
|
||||
|
||||
}
|
||||
+19
-4
@@ -60,6 +60,19 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* spel条件表达:判断小于3
|
||||
*
|
||||
* @param qjts 待判断的变量(可不传自行返回true或false)
|
||||
* @return boolean
|
||||
*/
|
||||
// public boolean eval(Integer qjts) {
|
||||
// if (qjts <= 3) {
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 查询请假
|
||||
*/
|
||||
@@ -142,11 +155,12 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
||||
*
|
||||
* @param processEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processEvent.flowCode.startsWith('leave')")
|
||||
@EventListener(condition = "#processEvent.flowCode.startsWith('leave') || #processEvent.flowCode.startsWith('hzdyjs-qj')")
|
||||
public void processHandler(ProcessEvent processEvent) {
|
||||
log.info("当前任务执行了{}", processEvent.toString());
|
||||
TestLeave testLeave = baseMapper.selectById(Long.valueOf(processEvent.getBusinessId()));
|
||||
testLeave.setStatus(processEvent.getStatus());
|
||||
// processEvent.getParams().put("qjts", 100);
|
||||
// 用于例如审批附件 审批意见等 存储到业务表内 自行根据业务实现存储流程
|
||||
Map<String, Object> params = processEvent.getParams();
|
||||
if (MapUtil.isNotEmpty(params)) {
|
||||
@@ -165,7 +179,8 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
||||
|
||||
/**
|
||||
* 执行任务创建监听
|
||||
* 示例:也可通过 @EventListener(condition = "#processTaskEvent.flowCode=='leave1'")进行判断
|
||||
* 示例:也可通过 @EventListener(condition =
|
||||
* "#processTaskEvent.flowCode=='leave1'")进行判断
|
||||
* 在方法中判断流程节点key
|
||||
* if ("xxx".equals(processTaskEvent.getNodeCode())) {
|
||||
* //执行业务逻辑
|
||||
@@ -173,7 +188,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
||||
*
|
||||
* @param processTaskEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processTaskEvent.flowCode.startsWith('leave')")
|
||||
@EventListener(condition = "#processTaskEvent.flowCode.startsWith('leave') || #processTaskEvent.flowCode.startsWith('hzdyjs-qj')")
|
||||
public void processTaskHandler(ProcessTaskEvent processTaskEvent) {
|
||||
log.info("当前任务创建了{}", processTaskEvent.toString());
|
||||
}
|
||||
@@ -185,7 +200,7 @@ public class TestLeaveServiceImpl implements ITestLeaveService {
|
||||
*
|
||||
* @param processDeleteEvent 参数
|
||||
*/
|
||||
@EventListener(condition = "#processDeleteEvent.flowCode.startsWith('leave')")
|
||||
@EventListener(condition = "#processDeleteEvent.flowCode.startsWith('leave') || #processDeleteEvent.flowCode.startsWith('hzdyjs-qj')")
|
||||
public void processDeleteHandler(ProcessDeleteEvent processDeleteEvent) {
|
||||
log.info("监听删除流程事件,当前任务执行了{}", processDeleteEvent.toString());
|
||||
TestLeave testLeave = baseMapper.selectById(Long.valueOf(processDeleteEvent.getBusinessId()));
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package org.dromara.workflow.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.workflow.domain.bo.XgStudentLeaveBo;
|
||||
import org.dromara.workflow.domain.vo.XgStudentLeaveVo;
|
||||
import org.dromara.workflow.domain.XgStudentLeave;
|
||||
import org.dromara.workflow.mapper.XgStudentLeaveMapper;
|
||||
import org.dromara.workflow.service.IXgStudentLeaveService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 学生请假 - 记录学生的请假申请、审批和销假信息Service业务层处理
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XgStudentLeaveServiceImpl implements IXgStudentLeaveService {
|
||||
|
||||
private final XgStudentLeaveMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*/
|
||||
@Override
|
||||
public XgStudentLeaveVo queryById(Long id){
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询学生请假 - 记录学生的请假申请、审批和销假信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生请假 - 记录学生的请假申请、审批和销假信息分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgStudentLeaveVo> queryPageList(XgStudentLeaveBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<XgStudentLeave> lqw = buildQueryWrapper(bo);
|
||||
Page<XgStudentLeaveVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的学生请假 - 记录学生的请假申请、审批和销假信息列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 学生请假 - 记录学生的请假申请、审批和销假信息列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgStudentLeaveVo> queryList(XgStudentLeaveBo bo) {
|
||||
LambdaQueryWrapper<XgStudentLeave> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<XgStudentLeave> buildQueryWrapper(XgStudentLeaveBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<XgStudentLeave> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(XgStudentLeave::getId);
|
||||
lqw.eq(bo.getDeleted() != null, XgStudentLeave::getDeleted, bo.getDeleted());
|
||||
lqw.eq(bo.getStudentId() != null, XgStudentLeave::getStudentId, bo.getStudentId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentName()), XgStudentLeave::getStudentName, bo.getStudentName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStudentNo()), XgStudentLeave::getStudentNo, bo.getStudentNo());
|
||||
lqw.eq(bo.getClassId() != null, XgStudentLeave::getClassId, bo.getClassId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getClassName()), XgStudentLeave::getClassName, bo.getClassName());
|
||||
lqw.eq(bo.getMajorId() != null, XgStudentLeave::getMajorId, bo.getMajorId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMajorName()), XgStudentLeave::getMajorName, bo.getMajorName());
|
||||
lqw.eq(bo.getCollegeId() != null, XgStudentLeave::getCollegeId, bo.getCollegeId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCollegeName()), XgStudentLeave::getCollegeName, bo.getCollegeName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getLeaveTypeCode()), XgStudentLeave::getLeaveTypeCode, bo.getLeaveTypeCode());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getLeaveTypeName()), XgStudentLeave::getLeaveTypeName, bo.getLeaveTypeName());
|
||||
lqw.eq(bo.getStartTime() != null, XgStudentLeave::getStartTime, bo.getStartTime());
|
||||
lqw.eq(bo.getEndTime() != null, XgStudentLeave::getEndTime, bo.getEndTime());
|
||||
lqw.eq(bo.getLeaveDuration() != null, XgStudentLeave::getLeaveDuration, bo.getLeaveDuration());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getIsLeaveSchool()), XgStudentLeave::getIsLeaveSchool, bo.getIsLeaveSchool());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getNeedCancel()), XgStudentLeave::getNeedCancel, bo.getNeedCancel());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getEmergencyContact()), XgStudentLeave::getEmergencyContact, bo.getEmergencyContact());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getEmergencyPhone()), XgStudentLeave::getEmergencyPhone, bo.getEmergencyPhone());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getLeaveReason()), XgStudentLeave::getLeaveReason, bo.getLeaveReason());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getLeaveLocation()), XgStudentLeave::getLeaveLocation, bo.getLeaveLocation());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getAttachmentOssIds()), XgStudentLeave::getAttachmentOssIds, bo.getAttachmentOssIds());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApprovalStatus()), XgStudentLeave::getApprovalStatus, bo.getApprovalStatus());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getApprovalOpinion()), XgStudentLeave::getApprovalOpinion, bo.getApprovalOpinion());
|
||||
lqw.eq(bo.getApprovalTime() != null, XgStudentLeave::getApprovalTime, bo.getApprovalTime());
|
||||
lqw.eq(bo.getApprovalBy() != null, XgStudentLeave::getApprovalBy, bo.getApprovalBy());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getApprovalByName()), XgStudentLeave::getApprovalByName, bo.getApprovalByName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getCancelStatus()), XgStudentLeave::getCancelStatus, bo.getCancelStatus());
|
||||
lqw.eq(bo.getCancelTime() != null, XgStudentLeave::getCancelTime, bo.getCancelTime());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getCancelLocation()), XgStudentLeave::getCancelLocation, bo.getCancelLocation());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getCancelPhotoOssIds()), XgStudentLeave::getCancelPhotoOssIds, bo.getCancelPhotoOssIds());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getCancelRemark()), XgStudentLeave::getCancelRemark, bo.getCancelRemark());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*
|
||||
* @param bo 学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(XgStudentLeaveBo bo) {
|
||||
XgStudentLeave add = MapstructUtils.convert(bo, XgStudentLeave.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
*
|
||||
* @param bo 学生请假 - 记录学生的请假申请、审批和销假信息
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(XgStudentLeaveBo bo) {
|
||||
XgStudentLeave update = MapstructUtils.convert(bo, XgStudentLeave.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(XgStudentLeave entity){
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除学生请假 - 记录学生的请假申请、审批和销假信息信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.workflow.mapper.XgStudentLeaveMapper">
|
||||
|
||||
</mapper>
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
package org.dromara.xg.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.xg.domain.vo.XgLeaveTypeConfigVo;
|
||||
import org.dromara.xg.domain.bo.XgLeaveTypeConfigBo;
|
||||
import org.dromara.xg.service.IXgLeaveTypeConfigService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 学生请假类型配置
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/xgLeaveTypeConfig/xgLeaveTypeConfig")
|
||||
public class XgLeaveTypeConfigController extends BaseController {
|
||||
|
||||
private final IXgLeaveTypeConfigService xgLeaveTypeConfigService;
|
||||
|
||||
/**
|
||||
* 查询学生请假类型配置列表
|
||||
*/
|
||||
@SaCheckPermission("xgLeaveTypeConfig:xgLeaveTypeConfig:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<XgLeaveTypeConfigVo> list(XgLeaveTypeConfigBo bo, PageQuery pageQuery) {
|
||||
return xgLeaveTypeConfigService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出学生请假类型配置列表
|
||||
*/
|
||||
@SaCheckPermission("xgLeaveTypeConfig:xgLeaveTypeConfig:export")
|
||||
@Log(title = "学生请假类型配置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(XgLeaveTypeConfigBo bo, HttpServletResponse response) {
|
||||
List<XgLeaveTypeConfigVo> list = xgLeaveTypeConfigService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "学生请假类型配置", XgLeaveTypeConfigVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生请假类型配置详细信息
|
||||
*
|
||||
* @param id 主键
|
||||
*/
|
||||
@SaCheckPermission("xgLeaveTypeConfig:xgLeaveTypeConfig:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<XgLeaveTypeConfigVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long id) {
|
||||
return R.ok(xgLeaveTypeConfigService.queryById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增学生请假类型配置
|
||||
*/
|
||||
@SaCheckPermission("xgLeaveTypeConfig:xgLeaveTypeConfig:add")
|
||||
@Log(title = "学生请假类型配置", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody XgLeaveTypeConfigBo bo) {
|
||||
return toAjax(xgLeaveTypeConfigService.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改学生请假类型配置
|
||||
*/
|
||||
@SaCheckPermission("xgLeaveTypeConfig:xgLeaveTypeConfig:edit")
|
||||
@Log(title = "学生请假类型配置", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody XgLeaveTypeConfigBo bo) {
|
||||
return toAjax(xgLeaveTypeConfigService.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除学生请假类型配置
|
||||
*
|
||||
* @param ids 主键串
|
||||
*/
|
||||
@SaCheckPermission("xgLeaveTypeConfig:xgLeaveTypeConfig:remove")
|
||||
@Log(title = "学生请假类型配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] ids) {
|
||||
return toAjax(xgLeaveTypeConfigService.deleteWithValidByIds(List.of(ids), true));
|
||||
}
|
||||
}
|
||||
+22
@@ -39,6 +39,7 @@ import org.dromara.common.excel.convert.ExcelDictPreloadConvert;
|
||||
import org.dromara.common.excel.service.SqlCacheConfigService;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.xg.domain.vo.XgStudentMsgVo;
|
||||
import org.dromara.xg.domain.bo.XgStudentMsgBo;
|
||||
import org.dromara.xg.domain.bo.XgStudentMsgAdvancedSearchBo;
|
||||
@@ -615,6 +616,27 @@ public class XgStudentMsgController extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户的学生信息
|
||||
*/
|
||||
@SaCheckPermission("studentMsg:studentMsg:query")
|
||||
@GetMapping("/currentUserInfo")
|
||||
public R<XgStudentMsgVo> getCurrentUserInfo() {
|
||||
// 获取当前登录用户ID
|
||||
Long userId = LoginHelper.getUserId();
|
||||
if (userId == null) {
|
||||
return R.fail("用户未登录");
|
||||
}
|
||||
|
||||
// 根据用户ID查询学生信息
|
||||
XgStudentMsgVo studentInfo = xgStudentMsgService.queryByUserId(userId);
|
||||
if (studentInfo == null) {
|
||||
return R.fail("未找到当前用户的学生信息");
|
||||
}
|
||||
|
||||
return R.ok(studentInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取学生信息详细信息
|
||||
*
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package org.dromara.xg.domain;
|
||||
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 学生请假类型配置对象 xg_leave_type_config
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("xg_leave_type_config")
|
||||
public class XgLeaveTypeConfig extends TenantEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Long deleted;
|
||||
|
||||
/**
|
||||
* 请假类型名称
|
||||
*/
|
||||
private String leaveTypeName;
|
||||
|
||||
/**
|
||||
* 请假类型编码
|
||||
*/
|
||||
private String leaveTypeCode;
|
||||
|
||||
/**
|
||||
* 请假类型描述
|
||||
*/
|
||||
private String leaveTypeDesc;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
private Long sortOrder;
|
||||
|
||||
/**
|
||||
* 请假是否需要上传地理位置:0-否,1-是
|
||||
*/
|
||||
private String needLocationOnApply;
|
||||
|
||||
/**
|
||||
* 销假是否必须上传照片:0-否,1-是
|
||||
*/
|
||||
private String needPhotoOnCancel;
|
||||
|
||||
/**
|
||||
* 销假是否需要上传地理位置:0-否,1-是
|
||||
*/
|
||||
private String needLocationOnCancel;
|
||||
|
||||
/**
|
||||
* 非离校请假是否需要销假:0-否,1-是
|
||||
*/
|
||||
private String needCancelForNonLeave;
|
||||
|
||||
/**
|
||||
* 是否可以提前请假:0-否,1-是
|
||||
*/
|
||||
private String canApplyInAdvance;
|
||||
|
||||
/**
|
||||
* 是否开启:0-关闭,1-开启
|
||||
*/
|
||||
private String isEnabled;
|
||||
|
||||
/**
|
||||
* 请假最大申请时长(天)
|
||||
*/
|
||||
private Double maxApplyDuration;
|
||||
|
||||
/**
|
||||
* 销假逾期多少时长给予提醒(天)
|
||||
*/
|
||||
private Double cancelOverdueReminder;
|
||||
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package org.dromara.xg.domain.bo;
|
||||
|
||||
import org.dromara.xg.domain.XgLeaveTypeConfig;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 学生请假类型配置业务对象 xg_leave_type_config
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = XgLeaveTypeConfig.class, reverseConvertGenerate = false)
|
||||
public class XgLeaveTypeConfigBo extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@NotNull(message = "主键ID(雪花ID)不能为空", groups = { EditGroup.class })
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 删除标志(0代表存在 1代表删除)
|
||||
*/
|
||||
private Long deleted;
|
||||
|
||||
/**
|
||||
* 请假类型名称
|
||||
*/
|
||||
@NotBlank(message = "请假类型名称不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String leaveTypeName;
|
||||
|
||||
/**
|
||||
* 请假类型编码
|
||||
*/
|
||||
@NotBlank(message = "请假类型编码不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String leaveTypeCode;
|
||||
|
||||
/**
|
||||
* 请假类型描述
|
||||
*/
|
||||
private String leaveTypeDesc;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
private Long sortOrder;
|
||||
|
||||
/**
|
||||
* 请假是否需要上传地理位置:0-否,1-是
|
||||
*/
|
||||
@NotBlank(message = "请假是否需要上传地理位置:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String needLocationOnApply;
|
||||
|
||||
/**
|
||||
* 销假是否必须上传照片:0-否,1-是
|
||||
*/
|
||||
@NotBlank(message = "销假是否必须上传照片:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String needPhotoOnCancel;
|
||||
|
||||
/**
|
||||
* 销假是否需要上传地理位置:0-否,1-是
|
||||
*/
|
||||
@NotBlank(message = "销假是否需要上传地理位置:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String needLocationOnCancel;
|
||||
|
||||
/**
|
||||
* 非离校请假是否需要销假:0-否,1-是
|
||||
*/
|
||||
@NotBlank(message = "非离校请假是否需要销假:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String needCancelForNonLeave;
|
||||
|
||||
/**
|
||||
* 是否可以提前请假:0-否,1-是
|
||||
*/
|
||||
@NotBlank(message = "是否可以提前请假:0-否,1-是不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String canApplyInAdvance;
|
||||
|
||||
/**
|
||||
* 是否开启:0-关闭,1-开启
|
||||
*/
|
||||
@NotBlank(message = "是否开启:0-关闭,1-开启不能为空", groups = { AddGroup.class, EditGroup.class })
|
||||
private String isEnabled;
|
||||
|
||||
/**
|
||||
* 请假最大申请时长(天)
|
||||
*/
|
||||
private Double maxApplyDuration;
|
||||
|
||||
/**
|
||||
* 销假逾期多少时长给予提醒(天)
|
||||
*/
|
||||
private Double cancelOverdueReminder;
|
||||
|
||||
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
package org.dromara.xg.domain.vo;
|
||||
|
||||
import org.dromara.xg.domain.XgLeaveTypeConfig;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 学生请假类型配置视图对象 xg_leave_type_config
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = XgLeaveTypeConfig.class)
|
||||
public class XgLeaveTypeConfigVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID(雪花ID)
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "雪=花ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 请假类型名称
|
||||
*/
|
||||
@ExcelProperty(value = "请假类型名称")
|
||||
private String leaveTypeName;
|
||||
|
||||
/**
|
||||
* 请假类型编码
|
||||
*/
|
||||
@ExcelProperty(value = "请假类型编码")
|
||||
private String leaveTypeCode;
|
||||
|
||||
/**
|
||||
* 请假类型描述
|
||||
*/
|
||||
@ExcelProperty(value = "请假类型描述")
|
||||
private String leaveTypeDesc;
|
||||
|
||||
/**
|
||||
* 排序号
|
||||
*/
|
||||
@ExcelProperty(value = "排序号")
|
||||
private Long sortOrder;
|
||||
|
||||
/**
|
||||
* 请假是否需要上传地理位置:0-否,1-是
|
||||
*/
|
||||
@ExcelProperty(value = "请假是否需要上传地理位置:0-否,1-是", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yesno")
|
||||
private String needLocationOnApply;
|
||||
|
||||
/**
|
||||
* 销假是否必须上传照片:0-否,1-是
|
||||
*/
|
||||
@ExcelProperty(value = "销假是否必须上传照片:0-否,1-是", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yesno")
|
||||
private String needPhotoOnCancel;
|
||||
|
||||
/**
|
||||
* 销假是否需要上传地理位置:0-否,1-是
|
||||
*/
|
||||
@ExcelProperty(value = "销假是否需要上传地理位置:0-否,1-是", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yesno")
|
||||
private String needLocationOnCancel;
|
||||
|
||||
/**
|
||||
* 非离校请假是否需要销假:0-否,1-是
|
||||
*/
|
||||
@ExcelProperty(value = "非离校请假是否需要销假:0-否,1-是", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yesno")
|
||||
private String needCancelForNonLeave;
|
||||
|
||||
/**
|
||||
* 是否可以提前请假:0-否,1-是
|
||||
*/
|
||||
@ExcelProperty(value = "是否可以提前请假:0-否,1-是", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yesno")
|
||||
private String canApplyInAdvance;
|
||||
|
||||
/**
|
||||
* 是否开启:0-关闭,1-开启
|
||||
*/
|
||||
@ExcelProperty(value = "是否开启:0-关闭,1-开启", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_yesno")
|
||||
private String isEnabled;
|
||||
|
||||
/**
|
||||
* 请假最大申请时长(天)
|
||||
*/
|
||||
@ExcelProperty(value = "请假最大申请时长", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "天=")
|
||||
private Double maxApplyDuration;
|
||||
|
||||
/**
|
||||
* 销假逾期多少时长给予提醒(天)
|
||||
*/
|
||||
@ExcelProperty(value = "销假逾期多少时长给予提醒", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "天=")
|
||||
private Double cancelOverdueReminder;
|
||||
|
||||
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package org.dromara.xg.mapper;
|
||||
|
||||
import org.dromara.xg.domain.XgLeaveTypeConfig;
|
||||
import org.dromara.xg.domain.vo.XgLeaveTypeConfigVo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* 学生请假类型配置Mapper接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
public interface XgLeaveTypeConfigMapper extends BaseMapperPlus<XgLeaveTypeConfig, XgLeaveTypeConfigVo> {
|
||||
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package org.dromara.xg.service;
|
||||
|
||||
import org.dromara.xg.domain.vo.XgLeaveTypeConfigVo;
|
||||
import org.dromara.xg.domain.bo.XgLeaveTypeConfigBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 学生请假类型配置Service接口
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
public interface IXgLeaveTypeConfigService {
|
||||
|
||||
/**
|
||||
* 查询学生请假类型配置
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 学生请假类型配置
|
||||
*/
|
||||
XgLeaveTypeConfigVo queryById(Long id);
|
||||
|
||||
/**
|
||||
* 分页查询学生请假类型配置列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生请假类型配置分页列表
|
||||
*/
|
||||
TableDataInfo<XgLeaveTypeConfigVo> queryPageList(XgLeaveTypeConfigBo bo, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询符合条件的学生请假类型配置列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 学生请假类型配置列表
|
||||
*/
|
||||
List<XgLeaveTypeConfigVo> queryList(XgLeaveTypeConfigBo bo);
|
||||
|
||||
/**
|
||||
* 新增学生请假类型配置
|
||||
*
|
||||
* @param bo 学生请假类型配置
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(XgLeaveTypeConfigBo bo);
|
||||
|
||||
/**
|
||||
* 修改学生请假类型配置
|
||||
*
|
||||
* @param bo 学生请假类型配置
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(XgLeaveTypeConfigBo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除学生请假类型配置信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
+8
@@ -98,6 +98,14 @@ public interface IXgStudentMsgService {
|
||||
*/
|
||||
XgStudentMsgVo queryPersonalInfo(Long userId);
|
||||
|
||||
/**
|
||||
* 根据用户ID查询学生信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 学生信息
|
||||
*/
|
||||
XgStudentMsgVo queryByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 根据班级ID和姓名查询学生信息列表
|
||||
*
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
package org.dromara.xg.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.dromara.xg.domain.bo.XgLeaveTypeConfigBo;
|
||||
import org.dromara.xg.domain.vo.XgLeaveTypeConfigVo;
|
||||
import org.dromara.xg.domain.XgLeaveTypeConfig;
|
||||
import org.dromara.xg.mapper.XgLeaveTypeConfigMapper;
|
||||
import org.dromara.xg.service.IXgLeaveTypeConfigService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 学生请假类型配置Service业务层处理
|
||||
*
|
||||
* @author zlwu
|
||||
* @date 2025-08-03
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class XgLeaveTypeConfigServiceImpl implements IXgLeaveTypeConfigService {
|
||||
|
||||
private final XgLeaveTypeConfigMapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询学生请假类型配置
|
||||
*
|
||||
* @param id 主键
|
||||
* @return 学生请假类型配置
|
||||
*/
|
||||
@Override
|
||||
public XgLeaveTypeConfigVo queryById(Long id) {
|
||||
return baseMapper.selectVoById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询学生请假类型配置列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 学生请假类型配置分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgLeaveTypeConfigVo> queryPageList(XgLeaveTypeConfigBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<XgLeaveTypeConfig> lqw = buildQueryWrapper(bo);
|
||||
Page<XgLeaveTypeConfigVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询符合条件的学生请假类型配置列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return 学生请假类型配置列表
|
||||
*/
|
||||
@Override
|
||||
public List<XgLeaveTypeConfigVo> queryList(XgLeaveTypeConfigBo bo) {
|
||||
LambdaQueryWrapper<XgLeaveTypeConfig> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<XgLeaveTypeConfig> buildQueryWrapper(XgLeaveTypeConfigBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<XgLeaveTypeConfig> lqw = Wrappers.lambdaQuery();
|
||||
lqw.orderByAsc(XgLeaveTypeConfig::getSortOrder);
|
||||
lqw.orderByAsc(XgLeaveTypeConfig::getId);
|
||||
lqw.eq(bo.getDeleted() != null, XgLeaveTypeConfig::getDeleted, bo.getDeleted());
|
||||
lqw.eq(bo.getIsEnabled() != null, XgLeaveTypeConfig::getIsEnabled, bo.getIsEnabled());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getLeaveTypeName()), XgLeaveTypeConfig::getLeaveTypeName,
|
||||
bo.getLeaveTypeName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getLeaveTypeCode()), XgLeaveTypeConfig::getLeaveTypeCode,
|
||||
bo.getLeaveTypeCode());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增学生请假类型配置
|
||||
*
|
||||
* @param bo 学生请假类型配置
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(XgLeaveTypeConfigBo bo) {
|
||||
XgLeaveTypeConfig add = MapstructUtils.convert(bo, XgLeaveTypeConfig.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setId(add.getId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改学生请假类型配置
|
||||
*
|
||||
* @param bo 学生请假类型配置
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(XgLeaveTypeConfigBo bo) {
|
||||
XgLeaveTypeConfig update = MapstructUtils.convert(bo, XgLeaveTypeConfig.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(XgLeaveTypeConfig entity) {
|
||||
// TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除学生请假类型配置信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
+14
@@ -663,6 +663,20 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService {
|
||||
.eq(XgStudentMsg::getId, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询学生信息
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 学生信息
|
||||
*/
|
||||
@Override
|
||||
public XgStudentMsgVo queryByUserId(Long userId) {
|
||||
// deleted 为0 且 用户ID为userId
|
||||
return baseMapper.selectVoOne(new LambdaQueryWrapper<XgStudentMsg>()
|
||||
.eq(XgStudentMsg::getDeleted, 0)
|
||||
.eq(XgStudentMsg::getId, userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据班级ID和姓名查询学生信息列表
|
||||
*
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.xg.mapper.XgLeaveTypeConfigMapper">
|
||||
|
||||
</mapper>
|
||||
@@ -39,6 +39,12 @@
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-excel</artifactId>
|
||||
</dependency>
|
||||
<!-- Apache POI for Excel export -->
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.2.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库 -->
|
||||
<dependency>
|
||||
@@ -76,6 +82,18 @@
|
||||
<artifactId>ruoyi-common-translation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token认证模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-satoken</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 系统管理模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
package org.dromara.xljk.controller;
|
||||
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationAppointmentBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationAppointmentVo;
|
||||
import org.dromara.xljk.domain.vo.TimeSlotDetailVo;
|
||||
import org.dromara.xljk.service.IXljkConsultationAppointmentService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.apache.poi.xssf.usermodel.XSSFSheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFRow;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/xljk/consultation/appointment")
|
||||
public class XljkConsultationAppointmentController extends BaseController {
|
||||
private static final Logger log = LoggerFactory.getLogger(XljkConsultationAppointmentController.class);
|
||||
|
||||
@Autowired
|
||||
private IXljkConsultationAppointmentService service;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<XljkConsultationAppointmentVo> list(XljkConsultationAppointmentBo bo, PageQuery pageQuery) {
|
||||
return service.selectPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R<XljkConsultationAppointmentVo> get(@PathVariable Long id) {
|
||||
log.info("查询预约记录详情,ID: {}", id);
|
||||
XljkConsultationAppointmentVo vo = service.selectById(id);
|
||||
log.info("查询结果: {}", vo);
|
||||
if (vo == null) {
|
||||
log.warn("未找到ID为{}的预约记录", id);
|
||||
return R.fail("未找到预约记录");
|
||||
}
|
||||
return R.ok(vo);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R<Boolean> add(@RequestBody XljkConsultationAppointmentBo bo) {
|
||||
boolean result = service.insert(bo);
|
||||
if (result) {
|
||||
return R.ok(true);
|
||||
} else {
|
||||
return R.fail("新增失败");
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public R<Boolean> edit(@RequestBody XljkConsultationAppointmentBo bo) {
|
||||
boolean result = service.update(bo);
|
||||
if (result) {
|
||||
return R.ok(true);
|
||||
} else {
|
||||
return R.fail("更新失败,预约记录不存在或已被修改");
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public R<Boolean> remove(@PathVariable Long id) {
|
||||
boolean result = service.deleteById(id);
|
||||
if (result) {
|
||||
return R.ok(true);
|
||||
} else {
|
||||
return R.fail("删除失败,预约记录不存在");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可预约时段列表(用于日历视图)
|
||||
*/
|
||||
@GetMapping("/available-slots")
|
||||
public R<List<Map<String, Object>>> getAvailableTimeSlots(
|
||||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
|
||||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {
|
||||
List<Map<String, Object>> slots = service.getAvailableTimeSlots(startDate, endDate);
|
||||
return R.ok(slots);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用的详细时段列表(30分钟一个时段)
|
||||
*/
|
||||
@GetMapping("/available-detail-slots")
|
||||
public R<List<TimeSlotDetailVo>> getAvailableDetailSlots(
|
||||
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date date,
|
||||
@RequestParam String timeSlot) {
|
||||
List<TimeSlotDetailVo> detailSlots = service.getAvailableDetailSlots(date, timeSlot);
|
||||
return R.ok(detailSlots);
|
||||
}
|
||||
|
||||
/**
|
||||
* 学生提交预约
|
||||
*/
|
||||
@PostMapping("/submit")
|
||||
public R<Boolean> submitAppointment(@RequestBody XljkConsultationAppointmentBo bo) {
|
||||
boolean result = service.submitAppointment(bo);
|
||||
if (result) {
|
||||
return R.ok(true);
|
||||
} else {
|
||||
return R.fail("预约失败,该时段可能已被预约");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的预约记录(学生用)
|
||||
*/
|
||||
@GetMapping("/my-appointments/{studentId}")
|
||||
public R<List<XljkConsultationAppointmentVo>> getMyAppointments(
|
||||
@PathVariable Long studentId,
|
||||
@RequestParam(required = false) Boolean force,
|
||||
HttpServletResponse response) {
|
||||
|
||||
log.info("获取我的预约记录,studentId: {}, force: {}", studentId, force);
|
||||
|
||||
// 添加缓存控制头,确保不被缓存
|
||||
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
response.setHeader("Pragma", "no-cache");
|
||||
response.setDateHeader("Expires", 0);
|
||||
|
||||
List<XljkConsultationAppointmentVo> list = service.getMyAppointments(studentId);
|
||||
log.info("查询结果数量: {}", list.size());
|
||||
|
||||
// 日志记录每条记录的状态,便于排查
|
||||
for (XljkConsultationAppointmentVo vo : list) {
|
||||
log.info("预约记录 ID: {}, 状态: {}, 日期: {}",
|
||||
vo.getId(), vo.getStatus(), vo.getAppointmentDate());
|
||||
}
|
||||
|
||||
return R.ok(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录咨询结果
|
||||
*/
|
||||
@PostMapping("/record-consultation/{id}")
|
||||
public R<Boolean> recordConsultation(
|
||||
@PathVariable Long id,
|
||||
@RequestBody Map<String, Object> requestBody) {
|
||||
|
||||
log.info("记录咨询结果,ID: {}, 请求体: {}", id, requestBody);
|
||||
|
||||
// 从请求体中获取参数
|
||||
String status = requestBody.get("status").toString();
|
||||
Date actualVisitTime = null;
|
||||
Integer communicationDuration = null;
|
||||
String consultationContent = "";
|
||||
String counselorSuggestion = "";
|
||||
|
||||
// 处理actualVisitTime
|
||||
if (requestBody.get("actualVisitTime") != null) {
|
||||
try {
|
||||
String actualVisitTimeStr = requestBody.get("actualVisitTime").toString();
|
||||
log.info("解析实际到访时间字符串: {}", actualVisitTimeStr);
|
||||
|
||||
// 尝试多种日期格式
|
||||
SimpleDateFormat[] dateFormats = {
|
||||
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"),
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"),
|
||||
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"),
|
||||
new SimpleDateFormat("yyyy-MM-dd")
|
||||
};
|
||||
|
||||
boolean parsed = false;
|
||||
for (SimpleDateFormat sdf : dateFormats) {
|
||||
try {
|
||||
actualVisitTime = sdf.parse(actualVisitTimeStr);
|
||||
parsed = true;
|
||||
log.info("成功解析实际到访时间: {}, 使用格式: {}", actualVisitTime, sdf.toPattern());
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
// 继续尝试下一个格式
|
||||
}
|
||||
}
|
||||
|
||||
if (!parsed) {
|
||||
log.error("无法解析实际到访时间: {}", actualVisitTimeStr);
|
||||
// 使用当前时间作为默认值
|
||||
actualVisitTime = new Date();
|
||||
log.info("使用当前时间作为默认值: {}", actualVisitTime);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析actualVisitTime失败", e);
|
||||
// 使用当前时间作为默认值
|
||||
actualVisitTime = new Date();
|
||||
log.info("使用当前时间作为默认值: {}", actualVisitTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理communicationDuration
|
||||
if (requestBody.get("communicationDuration") != null) {
|
||||
try {
|
||||
communicationDuration = Integer.parseInt(requestBody.get("communicationDuration").toString());
|
||||
} catch (Exception e) {
|
||||
log.error("解析communicationDuration失败", e);
|
||||
communicationDuration = 30; // 默认30分钟
|
||||
}
|
||||
}
|
||||
|
||||
// 处理consultationContent
|
||||
if (requestBody.get("consultationContent") != null) {
|
||||
consultationContent = requestBody.get("consultationContent").toString();
|
||||
}
|
||||
|
||||
// 处理counselorSuggestion
|
||||
if (requestBody.get("counselorSuggestion") != null) {
|
||||
counselorSuggestion = requestBody.get("counselorSuggestion").toString();
|
||||
}
|
||||
|
||||
boolean result = service.recordConsultation(id, actualVisitTime, communicationDuration,
|
||||
consultationContent, counselorSuggestion, status);
|
||||
if (result) {
|
||||
return R.ok(true);
|
||||
} else {
|
||||
return R.fail("记录失败,预约记录不存在");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取院系选项
|
||||
*/
|
||||
@GetMapping("/options/colleges")
|
||||
public R<List<Map<String, Object>>> getCollegeOptions() {
|
||||
log.info("获取院系选项");
|
||||
List<Map<String, Object>> result = service.getCollegeOptions();
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取专业选项
|
||||
*/
|
||||
@GetMapping("/options/majors")
|
||||
public R<List<Map<String, Object>>> getMajorOptions(@RequestParam(required = false) String collegeName) {
|
||||
log.info("获取专业选项,院系名称: {}", collegeName);
|
||||
List<Map<String, Object>> result = service.getMajorOptions(collegeName);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取班级选项
|
||||
*/
|
||||
@GetMapping("/options/classes")
|
||||
public R<List<Map<String, Object>>> getClassOptions(
|
||||
@RequestParam(required = false) String collegeName,
|
||||
@RequestParam(required = false) String majorName
|
||||
) {
|
||||
log.info("获取班级选项,院系名称: {}, 专业名称: {}", collegeName, majorName);
|
||||
List<Map<String, Object>> result = service.getClassOptions(collegeName, majorName);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出预约记录(Excel格式)
|
||||
*/
|
||||
@SaCheckPermission("xljk:consultationappointment:export")
|
||||
@CrossOrigin(origins = "*", allowedHeaders = "*", exposedHeaders = {"Content-Disposition"}, methods = {RequestMethod.GET})
|
||||
@GetMapping("/list/export")
|
||||
public ResponseEntity<byte[]> export(XljkConsultationAppointmentBo bo) throws IOException {
|
||||
log.info("导出预约记录(Excel),查询条件: {}", bo);
|
||||
List<XljkConsultationAppointmentVo> list = service.selectList(bo);
|
||||
|
||||
// 创建Excel
|
||||
XSSFWorkbook workbook = new XSSFWorkbook();
|
||||
XSSFSheet sheet = workbook.createSheet("预约记录");
|
||||
|
||||
// 表头
|
||||
String[] headers = {"序号", "学生姓名", "学号", "院系", "专业", "班级", "咨询原因", "咨询师", "预约日期", "预约时段", "状态", "咨询结果", "实际到访时间", "沟通时长", "咨询内容", "咨询师建议"};
|
||||
XSSFRow headerRow = sheet.createRow(0);
|
||||
for (int i = 0; i < headers.length; i++) {
|
||||
headerRow.createCell(i).setCellValue(headers[i]);
|
||||
}
|
||||
|
||||
// 数据
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
XljkConsultationAppointmentVo vo = list.get(i);
|
||||
XSSFRow row = sheet.createRow(i + 1);
|
||||
int col = 0;
|
||||
row.createCell(col++).setCellValue(i + 1);
|
||||
row.createCell(col++).setCellValue(vo.getStudentName());
|
||||
row.createCell(col++).setCellValue(vo.getStudentNo());
|
||||
row.createCell(col++).setCellValue(vo.getCollegeName());
|
||||
row.createCell(col++).setCellValue(vo.getMajorName());
|
||||
row.createCell(col++).setCellValue(vo.getClassName());
|
||||
row.createCell(col++).setCellValue(vo.getReason());
|
||||
row.createCell(col++).setCellValue(vo.getCounselorName());
|
||||
row.createCell(col++).setCellValue(vo.getAppointmentDate() != null ? dateFormat.format(vo.getAppointmentDate()) : "");
|
||||
row.createCell(col++).setCellValue(vo.getAppointmentDetailTime());
|
||||
// 状态
|
||||
String status = "";
|
||||
if (vo.getStatus() != null) {
|
||||
switch (vo.getStatus()) {
|
||||
case 0: status = "待咨询"; break;
|
||||
case 1: status = "已到访"; break;
|
||||
case 2: status = "已取消"; break;
|
||||
case 3: status = "未到访"; break;
|
||||
default: status = "未知状态";
|
||||
}
|
||||
}
|
||||
row.createCell(col++).setCellValue(status);
|
||||
row.createCell(col++).setCellValue(status); // 咨询结果
|
||||
row.createCell(col++).setCellValue(vo.getActualVisitTime() != null ? dateTimeFormat.format(vo.getActualVisitTime()) : "");
|
||||
row.createCell(col++).setCellValue(vo.getCommunicationDuration() != null ? vo.getCommunicationDuration().toString() : "");
|
||||
row.createCell(col++).setCellValue(vo.getConsultationContent());
|
||||
row.createCell(col++).setCellValue(vo.getCounselorSuggestion());
|
||||
}
|
||||
|
||||
// 写入字节流
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
workbook.write(out);
|
||||
workbook.close();
|
||||
byte[] data = out.toByteArray();
|
||||
|
||||
// 设置文件名
|
||||
String fileName = "预约记录_" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".xlsx";
|
||||
HttpHeaders headersHttp = new HttpHeaders();
|
||||
headersHttp.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
headersHttp.setContentDispositionFormData("attachment", fileName);
|
||||
|
||||
// 移除这些手动添加的CORS头,因为@CrossOrigin注解已经处理了CORS
|
||||
// headersHttp.add("Access-Control-Allow-Origin", "*");
|
||||
// headersHttp.add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
||||
// headersHttp.add("Access-Control-Allow-Headers", "*");
|
||||
// headersHttp.add("Access-Control-Expose-Headers", "Content-Disposition");
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.headers(headersHttp)
|
||||
.contentLength(data.length)
|
||||
.body(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义CSV字段中的特殊字符
|
||||
*/
|
||||
private String escapeCSV(String field) {
|
||||
if (field == null) {
|
||||
return "";
|
||||
}
|
||||
// 如果字段包含逗号、双引号或换行符,则用双引号包围,并将字段中的双引号替换为两个双引号
|
||||
if (field.contains(",") || field.contains("\"") || field.contains("\n")) {
|
||||
return "\"" + field.replace("\"", "\"\"") + "\"";
|
||||
}
|
||||
return field;
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package org.dromara.xljk.controller;
|
||||
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationCounselorBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationCounselorVo;
|
||||
import org.dromara.xljk.service.IXljkConsultationCounselorService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/xljk/consultation/counselor")
|
||||
public class XljkConsultationCounselorController {
|
||||
@Autowired
|
||||
private IXljkConsultationCounselorService service;
|
||||
|
||||
@GetMapping("/list")
|
||||
public List<XljkConsultationCounselorVo> list(XljkConsultationCounselorBo bo) {
|
||||
return service.selectList(bo);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public XljkConsultationCounselorVo get(@PathVariable Long id) {
|
||||
return service.selectById(id);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public boolean add(@RequestBody XljkConsultationCounselorBo bo) {
|
||||
return service.insert(bo);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public boolean edit(@RequestBody XljkConsultationCounselorBo bo) {
|
||||
return service.update(bo);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public boolean remove(@PathVariable Long id) {
|
||||
return service.deleteById(id);
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package org.dromara.xljk.controller;
|
||||
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 心理咨询预约调试控制器
|
||||
* 注意:此控制器仅用于开发环境调试,生产环境应该移除
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/xljk/consultation/debug")
|
||||
public class XljkConsultationDebugController {
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
/**
|
||||
* 执行SQL查询
|
||||
*
|
||||
* @param params 包含SQL语句的参数对象
|
||||
* @return 查询结果
|
||||
*/
|
||||
@PostMapping("/execute-sql")
|
||||
public R<List<Map<String, Object>>> executeSql(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
String sql = params.get("sql");
|
||||
if (sql == null || sql.trim().isEmpty()) {
|
||||
return R.fail("SQL语句不能为空");
|
||||
}
|
||||
|
||||
// 安全检查,只允许SELECT语句
|
||||
sql = sql.trim();
|
||||
if (!sql.toLowerCase().startsWith("select")) {
|
||||
return R.fail("只允许执行SELECT语句");
|
||||
}
|
||||
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql);
|
||||
return R.ok(result);
|
||||
} catch (Exception e) {
|
||||
return R.fail("执行SQL失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生预约记录
|
||||
*
|
||||
* @param studentId 学生ID
|
||||
* @return 预约记录
|
||||
*/
|
||||
@GetMapping("/appointments/{studentId}")
|
||||
public R<List<Map<String, Object>>> getAppointmentsByStudentId(@PathVariable String studentId) {
|
||||
try {
|
||||
String sql = "SELECT * FROM xljk_consultation_appointment WHERE student_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, studentId);
|
||||
return R.ok(result);
|
||||
} catch (Exception e) {
|
||||
return R.fail("查询失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询学生信息
|
||||
*
|
||||
* @param studentNo 学号
|
||||
* @return 学生信息
|
||||
*/
|
||||
@GetMapping("/student/{studentNo}")
|
||||
public R<Map<String, Object>> getStudentInfo(@PathVariable String studentNo) {
|
||||
try {
|
||||
// 这里假设学生信息存储在sys_user表中,可能需要根据实际情况调整
|
||||
String sql = "SELECT * FROM sys_user WHERE user_name = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, studentNo);
|
||||
|
||||
if (result.isEmpty()) {
|
||||
return R.fail("未找到该学号的学生信息");
|
||||
}
|
||||
|
||||
return R.ok(result.get(0));
|
||||
} catch (Exception e) {
|
||||
return R.fail("查询失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package org.dromara.xljk.controller;
|
||||
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.domain.model.LoginUser;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.satoken.utils.LoginHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationNoShowBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationNoShowVo;
|
||||
import org.dromara.xljk.service.IXljkConsultationNoShowService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 预约限制管理控制器
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/xljk/consultation/no-show")
|
||||
public class XljkConsultationNoShowController extends BaseController {
|
||||
@Autowired
|
||||
private IXljkConsultationNoShowService service;
|
||||
|
||||
/**
|
||||
* 查询未到访记录列表
|
||||
*/
|
||||
@SaCheckPermission("xljk:consultationnoshow:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<XljkConsultationNoShowVo> list(XljkConsultationNoShowBo bo, PageQuery pageQuery) {
|
||||
// 直接返回查询结果
|
||||
List<XljkConsultationNoShowVo> list = service.selectList(bo);
|
||||
return TableDataInfo.build(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未到访记录详情
|
||||
*/
|
||||
@SaCheckPermission("xljk:consultationnoshow:query")
|
||||
@GetMapping("/{id}")
|
||||
public R<XljkConsultationNoShowVo> get(@PathVariable Long id) {
|
||||
return R.ok(service.selectById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解除预约限制
|
||||
*/
|
||||
@SaCheckPermission("xljk:consultationnoshow:release")
|
||||
@PutMapping("/{id}/release")
|
||||
public R<Boolean> release(@PathVariable Long id) {
|
||||
return R.ok(service.releaseLimitation(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查学生是否被限制预约
|
||||
*/
|
||||
@GetMapping("/check-limitation")
|
||||
public R<Map<String, Object>> checkLimitation(@RequestParam Long studentId) {
|
||||
return R.ok(service.checkLimitation(studentId));
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package org.dromara.xljk.controller;
|
||||
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationRecordBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationRecordVo;
|
||||
import org.dromara.xljk.service.IXljkConsultationRecordService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/xljk/consultation/record")
|
||||
public class XljkConsultationRecordController {
|
||||
@Autowired
|
||||
private IXljkConsultationRecordService service;
|
||||
|
||||
@GetMapping("/list")
|
||||
public List<XljkConsultationRecordVo> list(XljkConsultationRecordBo bo) {
|
||||
return service.selectList(bo);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public XljkConsultationRecordVo get(@PathVariable Long id) {
|
||||
return service.selectById(id);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public boolean add(@RequestBody XljkConsultationRecordBo bo) {
|
||||
return service.insert(bo);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public boolean edit(@RequestBody XljkConsultationRecordBo bo) {
|
||||
return service.update(bo);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public boolean remove(@PathVariable Long id) {
|
||||
return service.deleteById(id);
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package org.dromara.xljk.controller;
|
||||
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationScheduleBo;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationScheduleBatchBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationScheduleVo;
|
||||
import org.dromara.xljk.service.IXljkConsultationScheduleService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationScheduleSummaryVo;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/xljk/consultation/schedule")
|
||||
public class XljkConsultationScheduleController {
|
||||
@Autowired
|
||||
private IXljkConsultationScheduleService service;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(XljkConsultationScheduleBo bo) {
|
||||
List<XljkConsultationScheduleSummaryVo> list = service.selectSummaryList(bo);
|
||||
TableDataInfo rspData = new TableDataInfo();
|
||||
rspData.setCode(200);
|
||||
rspData.setMsg("查询成功");
|
||||
rspData.setRows(list);
|
||||
rspData.setTotal(list.size());
|
||||
return rspData;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public XljkConsultationScheduleVo get(@PathVariable Long id) {
|
||||
return service.selectById(id);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R<Integer> add(@RequestBody Object requestBody) {
|
||||
// 判断请求体类型
|
||||
if (requestBody instanceof Map) {
|
||||
Map<String, Object> requestMap = (Map<String, Object>) requestBody;
|
||||
|
||||
// 检查是否包含批量创建的特定字段
|
||||
if (requestMap.containsKey("startDate") && requestMap.containsKey("endDate")) {
|
||||
// 批量创建预约时段
|
||||
XljkConsultationScheduleBatchBo batchBo = new XljkConsultationScheduleBatchBo();
|
||||
|
||||
// 设置必要字段
|
||||
if (requestMap.containsKey("counselorId")) {
|
||||
batchBo.setCounselorId(Long.valueOf(requestMap.get("counselorId").toString()));
|
||||
}
|
||||
|
||||
batchBo.setStartDate(requestMap.get("startDate").toString());
|
||||
batchBo.setEndDate(requestMap.get("endDate").toString());
|
||||
|
||||
// 设置上午时段
|
||||
if (requestMap.containsKey("morningEnabled")) {
|
||||
batchBo.setMorningEnabled(Boolean.valueOf(requestMap.get("morningEnabled").toString()));
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("morningStartTime")) {
|
||||
batchBo.setMorningStartTime(requestMap.get("morningStartTime").toString());
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("morningEndTime")) {
|
||||
batchBo.setMorningEndTime(requestMap.get("morningEndTime").toString());
|
||||
}
|
||||
|
||||
// 设置下午时段
|
||||
if (requestMap.containsKey("afternoonEnabled")) {
|
||||
batchBo.setAfternoonEnabled(Boolean.valueOf(requestMap.get("afternoonEnabled").toString()));
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("afternoonStartTime")) {
|
||||
batchBo.setAfternoonStartTime(requestMap.get("afternoonStartTime").toString());
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("afternoonEndTime")) {
|
||||
batchBo.setAfternoonEndTime(requestMap.get("afternoonEndTime").toString());
|
||||
}
|
||||
|
||||
// 设置其他字段
|
||||
if (requestMap.containsKey("status")) {
|
||||
batchBo.setStatus(requestMap.get("status").toString());
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("skipWeekends")) {
|
||||
batchBo.setSkipWeekends(Boolean.valueOf(requestMap.get("skipWeekends").toString()));
|
||||
}
|
||||
|
||||
// 调用批量创建方法
|
||||
int count = service.batchInsert(batchBo);
|
||||
return R.ok(count);
|
||||
}
|
||||
}
|
||||
|
||||
// 默认处理单个预约时段创建
|
||||
XljkConsultationScheduleBo bo = new XljkConsultationScheduleBo();
|
||||
if (requestBody instanceof Map) {
|
||||
Map<String, Object> requestMap = (Map<String, Object>) requestBody;
|
||||
|
||||
if (requestMap.containsKey("id")) {
|
||||
bo.setId(Long.valueOf(requestMap.get("id").toString()));
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("counselorId")) {
|
||||
bo.setCounselorId(Long.valueOf(requestMap.get("counselorId").toString()));
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("scheduleDate")) {
|
||||
// 处理日期格式
|
||||
// 这里可能需要根据实际情况调整
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("timeSlot")) {
|
||||
bo.setTimeSlot(requestMap.get("timeSlot").toString());
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("startTime")) {
|
||||
bo.setStartTime(requestMap.get("startTime").toString());
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("endTime")) {
|
||||
bo.setEndTime(requestMap.get("endTime").toString());
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("status")) {
|
||||
bo.setStatus(requestMap.get("status").toString());
|
||||
}
|
||||
|
||||
// 处理批量创建字段,确保类型正确
|
||||
if (requestMap.containsKey("morningEnabled")) {
|
||||
bo.setMorningEnabled(Boolean.valueOf(requestMap.get("morningEnabled").toString()));
|
||||
}
|
||||
|
||||
if (requestMap.containsKey("afternoonEnabled")) {
|
||||
bo.setAfternoonEnabled(Boolean.valueOf(requestMap.get("afternoonEnabled").toString()));
|
||||
}
|
||||
}
|
||||
|
||||
boolean success = service.insert(bo);
|
||||
return success ? R.ok(1) : R.fail("新增失败");
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public boolean edit(@RequestBody XljkConsultationScheduleBo bo) {
|
||||
return service.update(bo);
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public boolean remove(@PathVariable Long id) {
|
||||
return service.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取咨询师选项列表
|
||||
*
|
||||
* @return 咨询师选项列表
|
||||
*/
|
||||
@GetMapping("/options/counselors")
|
||||
public R<List<Map<String, Object>>> getCounselorOptions() {
|
||||
String sql = "SELECT u.user_id as id, u.nick_name as name FROM sys_user u " +
|
||||
"JOIN sys_user_role ur ON u.user_id = ur.user_id " +
|
||||
"JOIN sys_role r ON ur.role_id = r.role_id " +
|
||||
"WHERE r.role_key = 'xljk_consultant' AND u.del_flag = '0'";
|
||||
|
||||
List<Map<String, Object>> counselorOptions = jdbcTemplate.queryForList(sql);
|
||||
return R.ok(counselorOptions);
|
||||
}
|
||||
}
|
||||
+27
-5
@@ -22,6 +22,9 @@ import org.dromara.xljk.domain.vo.XljkEvaluationVo;
|
||||
import org.dromara.xljk.domain.bo.XljkEvaluationBo;
|
||||
import org.dromara.xljk.service.IXljkEvaluationService;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.xljk.domain.XljkEvaluationDetail;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
|
||||
/**
|
||||
* 心理健康测评Controller
|
||||
@@ -32,7 +35,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/xljk/evaluation")
|
||||
@RequestMapping("/api/xljk/evaluation")
|
||||
public class XljkEvaluationController extends BaseController {
|
||||
|
||||
private final IXljkEvaluationService evaluationService;
|
||||
@@ -54,6 +57,25 @@ public class XljkEvaluationController extends BaseController {
|
||||
@PostMapping("/export")
|
||||
public void export(XljkEvaluationBo bo, HttpServletResponse response) {
|
||||
List<XljkEvaluationVo> list = evaluationService.queryList(bo);
|
||||
|
||||
// 确保每条记录都有学生人数和重点关注人数
|
||||
for (XljkEvaluationVo vo : list) {
|
||||
if (vo.getStudentCount() == null || vo.getFocusCount() == null) {
|
||||
// 查询学生数量和重点关注数量
|
||||
Long evaluationId = vo.getId();
|
||||
LambdaQueryWrapper<XljkEvaluationDetail> detailLqw = Wrappers.lambdaQuery();
|
||||
detailLqw.eq(XljkEvaluationDetail::getEvaluationId, evaluationId);
|
||||
int studentCount = evaluationService.getDetailMapper().selectCount(detailLqw).intValue();
|
||||
vo.setStudentCount(studentCount);
|
||||
|
||||
detailLqw.clear();
|
||||
detailLqw.eq(XljkEvaluationDetail::getEvaluationId, evaluationId)
|
||||
.eq(XljkEvaluationDetail::getMentalStatus, "3");
|
||||
int focusCount = evaluationService.getDetailMapper().selectCount(detailLqw).intValue();
|
||||
vo.setFocusCount(focusCount);
|
||||
}
|
||||
}
|
||||
|
||||
ExcelUtil.exportExcel(list, "心理健康测评", XljkEvaluationVo.class, response);
|
||||
}
|
||||
|
||||
@@ -133,10 +155,10 @@ public class XljkEvaluationController extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布测评
|
||||
* 发布测评(已废弃,改为提交功能)
|
||||
*/
|
||||
@SaCheckPermission("xljk:evaluation:publish")
|
||||
@Log(title = "发布测评", businessType = BusinessType.UPDATE)
|
||||
@Log(title = "提交测评", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/{id}/publish")
|
||||
public R<Void> publishEvaluation(@NotNull(message = "测评ID不能为空") @PathVariable Long id) {
|
||||
@@ -144,10 +166,10 @@ public class XljkEvaluationController extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成测评
|
||||
* 提交测评
|
||||
*/
|
||||
@SaCheckPermission("xljk:evaluation:complete")
|
||||
@Log(title = "完成测评", businessType = BusinessType.UPDATE)
|
||||
@Log(title = "提交测评", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping("/{id}/complete")
|
||||
public R<Void> completeEvaluation(@NotNull(message = "测评ID不能为空") @PathVariable Long id) {
|
||||
|
||||
+74
-3
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
@@ -29,10 +30,11 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
* @author Cursor AI
|
||||
* @date 2025-07-02
|
||||
*/
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/xljk/evaluation/detail")
|
||||
@RequestMapping("/api/xljk/evaluation/detail")
|
||||
public class XljkEvaluationDetailController extends BaseController {
|
||||
|
||||
private final IXljkEvaluationDetailService detailService;
|
||||
@@ -53,8 +55,77 @@ public class XljkEvaluationDetailController extends BaseController {
|
||||
@Log(title = "心理健康测评明细", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(XljkEvaluationDetailBo bo, HttpServletResponse response) {
|
||||
List<XljkEvaluationDetailVo> list = detailService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "心理健康测评明细", XljkEvaluationDetailVo.class, response);
|
||||
log.info("导出心理健康测评明细,参数:{}", bo);
|
||||
|
||||
try {
|
||||
List<XljkEvaluationDetailVo> list;
|
||||
|
||||
// 如果只传了evaluationId参数,需要构建查询条件
|
||||
if (bo.getEvaluationId() != null && bo.getEvaluationIdIn() == null) {
|
||||
log.info("根据evaluationId查询明细:{}", bo.getEvaluationId());
|
||||
list = detailService.queryByEvaluationId(bo.getEvaluationId());
|
||||
log.info("查询到{}条记录", list.size());
|
||||
} else {
|
||||
// 正常查询流程
|
||||
list = detailService.queryList(bo);
|
||||
log.info("查询到{}条记录", list.size());
|
||||
}
|
||||
|
||||
// 数据预处理,确保所有字段都有合适的值
|
||||
for (XljkEvaluationDetailVo vo : list) {
|
||||
// 处理可能为null的字段
|
||||
if (vo.getGender() == null) {
|
||||
vo.setGender("2"); // 默认为未知性别
|
||||
}
|
||||
if (vo.getMentalStatus() == null) {
|
||||
vo.setMentalStatus("1"); // 默认为健康状态
|
||||
}
|
||||
// 确保其他必要字段有值
|
||||
if (vo.getStudentName() == null) {
|
||||
vo.setStudentName("");
|
||||
}
|
||||
if (vo.getStudentNo() == null) {
|
||||
vo.setStudentNo("");
|
||||
}
|
||||
if (vo.getPhone() == null) {
|
||||
vo.setPhone("");
|
||||
}
|
||||
if (vo.getRemark() == null) {
|
||||
vo.setRemark("");
|
||||
}
|
||||
|
||||
// 手动处理日期格式
|
||||
if (vo.getBirthDate() != null) {
|
||||
// 创建一个新的日期对象,只保留年月日
|
||||
java.util.Calendar cal = java.util.Calendar.getInstance();
|
||||
cal.setTime(vo.getBirthDate());
|
||||
cal.set(java.util.Calendar.HOUR_OF_DAY, 0);
|
||||
cal.set(java.util.Calendar.MINUTE, 0);
|
||||
cal.set(java.util.Calendar.SECOND, 0);
|
||||
cal.set(java.util.Calendar.MILLISECOND, 0);
|
||||
vo.setBirthDate(cal.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("开始导出Excel,记录数:{}", list.size());
|
||||
|
||||
// 使用自定义导出方法,确保列宽适配内容
|
||||
ExcelUtil.exportExcel(list, "心理健康测评明细", XljkEvaluationDetailVo.class, response);
|
||||
|
||||
log.info("导出Excel成功");
|
||||
} catch (Exception e) {
|
||||
log.error("导出心理健康测评明细异常", e);
|
||||
log.error("异常详情: {}", e.getMessage());
|
||||
// 尝试向客户端返回错误信息
|
||||
try {
|
||||
response.reset();
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.getWriter().println("{\"code\":500,\"msg\":\"导出失败: " + e.getMessage() + "\"}");
|
||||
} catch (Exception ex) {
|
||||
log.error("返回错误信息异常", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package org.dromara.xljk.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationAppointment implements Serializable {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long studentId;
|
||||
private Long counselorId;
|
||||
private Long scheduleId;
|
||||
private Date appointmentDate;
|
||||
private String appointmentTime;
|
||||
private String appointmentDetailTime; // 具体预约时间段,如"08:30-09:00"
|
||||
private String reason;
|
||||
private String status;
|
||||
private Date actualVisitTime;
|
||||
private Integer communicationDuration;
|
||||
private String consultationContent;
|
||||
private String counselorSuggestion;
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package org.dromara.xljk.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationCounselor implements Serializable {
|
||||
private Long id; // 主键ID
|
||||
private String tenantId; // 租户编号
|
||||
private Long createDept; // 创建部门
|
||||
private Long createBy; // 创建者
|
||||
private Date createTime; // 创建时间
|
||||
private Long updateBy; // 更新者
|
||||
private Date updateTime; // 更新时间
|
||||
private Integer deleted; // 删除标志(0代表存在 1代表删除)
|
||||
private String name; // 咨询师姓名
|
||||
private String workNo; // 工号
|
||||
private String title; // 职称
|
||||
private String specialty; // 专长领域
|
||||
private String introduction; // 简介
|
||||
private String status; // 状态(0正常 1停用)
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package org.dromara.xljk.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationNoShow implements Serializable {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long studentId;
|
||||
private Long appointmentId;
|
||||
private Date noShowDate;
|
||||
private Date expireDate;
|
||||
private String status;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package org.dromara.xljk.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationRecord implements Serializable {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long appointmentId;
|
||||
private String visitStatus;
|
||||
private Integer duration;
|
||||
private String content;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.dromara.xljk.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationSchedule implements Serializable {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long counselorId;
|
||||
private Date scheduleDate;
|
||||
private String timeSlot; // 0上午 1下午
|
||||
private String startTime; // 开始时间 HH:mm 格式
|
||||
private String endTime; // 结束时间 HH:mm 格式
|
||||
private String status; // 0正常 1停用
|
||||
private String batchId; // 批次ID,用于标识同一批次创建的预约时段
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.dromara.xljk.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationAppointmentBo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long studentId;
|
||||
private Long counselorId;
|
||||
private Long scheduleId;
|
||||
private Date appointmentDate;
|
||||
private String appointmentTime;
|
||||
private String appointmentDetailTime; // 具体预约时间段,如"08:30-09:00"
|
||||
private String reason;
|
||||
private String status;
|
||||
private Date actualVisitTime;
|
||||
private Integer communicationDuration;
|
||||
private String consultationContent;
|
||||
private String counselorSuggestion;
|
||||
|
||||
// 查询参数字段
|
||||
private String studentName;
|
||||
private String studentNo;
|
||||
private String collegeName;
|
||||
private String majorName;
|
||||
private String className;
|
||||
|
||||
// 分页和排序参数
|
||||
private Integer pageNum;
|
||||
private Integer pageSize;
|
||||
|
||||
// 额外查询参数
|
||||
private Map<String, Object> params = new HashMap<>();
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package org.dromara.xljk.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationCounselorBo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private String name;
|
||||
private String workNo;
|
||||
private String title;
|
||||
private String specialty;
|
||||
private String introduction;
|
||||
private String status;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package org.dromara.xljk.domain.bo;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationNoShowBo {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名(用于查询)
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号(用于查询)
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 预约记录ID
|
||||
*/
|
||||
private Long appointmentId;
|
||||
|
||||
/**
|
||||
* 未到访日期
|
||||
*/
|
||||
private Date noShowDate;
|
||||
|
||||
/**
|
||||
* 限制到期日
|
||||
*/
|
||||
private Date expireDate;
|
||||
|
||||
/**
|
||||
* 状态(0生效中 1已过期 2已解除)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 分页参数
|
||||
*/
|
||||
private Integer pageNum;
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 其他查询参数
|
||||
*/
|
||||
private Map<String, Object> params;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package org.dromara.xljk.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationRecordBo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long appointmentId;
|
||||
private String visitStatus;
|
||||
private Integer duration;
|
||||
private String content;
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package org.dromara.xljk.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 批量创建预约时段的业务对象
|
||||
*/
|
||||
@Data
|
||||
public class XljkConsultationScheduleBatchBo {
|
||||
/**
|
||||
* 咨询师ID
|
||||
*/
|
||||
private Long counselorId;
|
||||
|
||||
/**
|
||||
* 开始日期
|
||||
*/
|
||||
private String startDate;
|
||||
|
||||
/**
|
||||
* 结束日期
|
||||
*/
|
||||
private String endDate;
|
||||
|
||||
/**
|
||||
* 是否启用上午时段
|
||||
*/
|
||||
private Boolean morningEnabled;
|
||||
|
||||
/**
|
||||
* 上午开始时间 (HH:mm)
|
||||
*/
|
||||
private String morningStartTime;
|
||||
|
||||
/**
|
||||
* 上午结束时间 (HH:mm)
|
||||
*/
|
||||
private String morningEndTime;
|
||||
|
||||
/**
|
||||
* 是否启用下午时段
|
||||
*/
|
||||
private Boolean afternoonEnabled;
|
||||
|
||||
/**
|
||||
* 下午开始时间 (HH:mm)
|
||||
*/
|
||||
private String afternoonStartTime;
|
||||
|
||||
/**
|
||||
* 下午结束时间 (HH:mm)
|
||||
*/
|
||||
private String afternoonEndTime;
|
||||
|
||||
/**
|
||||
* 状态 (0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 是否跳过周末
|
||||
*/
|
||||
private Boolean skipWeekends;
|
||||
|
||||
/**
|
||||
* 批次ID,用于标识同一批次创建的预约时段
|
||||
*/
|
||||
private String batchId;
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package org.dromara.xljk.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationScheduleBo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long counselorId;
|
||||
private Date scheduleDate;
|
||||
private String timeSlot; // 0上午 1下午
|
||||
private String startTime; // 开始时间 HH:mm 格式
|
||||
private String endTime; // 结束时间 HH:mm 格式
|
||||
private String status;
|
||||
|
||||
// 批量创建时使用的字段
|
||||
private Boolean morningEnabled;
|
||||
private String morningStartTime;
|
||||
private String morningEndTime;
|
||||
private Boolean afternoonEnabled;
|
||||
private String afternoonStartTime;
|
||||
private String afternoonEndTime;
|
||||
private Boolean skipWeekends;
|
||||
|
||||
// 保留这些字段是为了兼容旧代码,但不再使用
|
||||
private Integer maxAppointments;
|
||||
private Integer currentAppointments;
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 时段详情VO
|
||||
*/
|
||||
@Data
|
||||
public class TimeSlotDetailVo {
|
||||
|
||||
/**
|
||||
* 开始时间(HH:mm)
|
||||
*/
|
||||
private String startTime;
|
||||
|
||||
/**
|
||||
* 结束时间(HH:mm)
|
||||
*/
|
||||
private String endTime;
|
||||
|
||||
/**
|
||||
* 是否已预约(true已预约 false未预约)
|
||||
*/
|
||||
private Boolean isBooked;
|
||||
|
||||
/**
|
||||
* 是否已过期(true已过期 false未过期)
|
||||
*/
|
||||
private Boolean isExpired;
|
||||
|
||||
/**
|
||||
* 完整时段表示(如"08:30-09:00")
|
||||
*/
|
||||
private String timeSlot;
|
||||
|
||||
/**
|
||||
* 创建完整时段表示
|
||||
*/
|
||||
public void generateTimeSlot() {
|
||||
this.timeSlot = this.startTime + "-" + this.endTime;
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationAppointmentVo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
private Long updateBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
private Integer deleted;
|
||||
private Long studentId;
|
||||
private Long counselorId;
|
||||
private Long scheduleId;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date appointmentDate;
|
||||
|
||||
private String appointmentTime;
|
||||
private String appointmentDetailTime; // 具体预约时间段,如"08:30-09:00"
|
||||
private String reason;
|
||||
/**
|
||||
* 状态(0待咨询 1已完成 2已取消 3未到访)
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date actualVisitTime;
|
||||
|
||||
private Integer communicationDuration;
|
||||
private String consultationContent;
|
||||
private String counselorSuggestion;
|
||||
|
||||
// 关联信息展示字段,不存储在数据库
|
||||
private String studentName;
|
||||
private String studentNo;
|
||||
private String className;
|
||||
private String counselorName;
|
||||
|
||||
// 新增院系和专业字段
|
||||
private String collegeName; // 院系名称
|
||||
private String majorName; // 专业名称
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationCounselorVo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private String name;
|
||||
private String workNo;
|
||||
private String title;
|
||||
private String specialty;
|
||||
private String introduction;
|
||||
private String status;
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationNoShowVo {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
private Long createDept;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 删除标志
|
||||
*/
|
||||
private Integer deleted;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
* 学生姓名
|
||||
*/
|
||||
private String studentName;
|
||||
|
||||
/**
|
||||
* 学号
|
||||
*/
|
||||
private String studentNo;
|
||||
|
||||
/**
|
||||
* 院系
|
||||
*/
|
||||
private String collegeName;
|
||||
|
||||
/**
|
||||
* 专业
|
||||
*/
|
||||
private String majorName;
|
||||
|
||||
/**
|
||||
* 班级
|
||||
*/
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 咨询师名称
|
||||
*/
|
||||
private String counselorName;
|
||||
|
||||
/**
|
||||
* 预约日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date appointmentDate;
|
||||
|
||||
/**
|
||||
* 预约时段
|
||||
*/
|
||||
private String appointmentDetailTime;
|
||||
|
||||
/**
|
||||
* 咨询原因
|
||||
*/
|
||||
private String reason;
|
||||
|
||||
/**
|
||||
* 预约记录ID
|
||||
*/
|
||||
private Long appointmentId;
|
||||
|
||||
/**
|
||||
* 未到访日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date noShowDate;
|
||||
|
||||
/**
|
||||
* 限制到期日
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date expireDate;
|
||||
|
||||
/**
|
||||
* 状态(0生效中 1已过期 2已解除)
|
||||
*/
|
||||
private String status;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationRecordVo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long appointmentId;
|
||||
private String visitStatus;
|
||||
private Integer duration;
|
||||
private String content;
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 预约时段汇总视图对象
|
||||
*/
|
||||
@Data
|
||||
public class XljkConsultationScheduleSummaryVo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long counselorId;
|
||||
private String counselorName; // 咨询师姓名,用于前端显示
|
||||
|
||||
// 汇总信息
|
||||
private String dateRange; // 日期范围,如"2025-07-01 至 2025-07-10"
|
||||
private Boolean morningEnabled; // 是否启用上午时段
|
||||
private String morningTime; // 上午时间,如"08:30-12:00"
|
||||
private Boolean afternoonEnabled; // 是否启用下午时段
|
||||
private String afternoonTime; // 下午时间,如"14:30-17:00"
|
||||
private String status; // 状态
|
||||
private Integer scheduleCount; // 预约时段数量
|
||||
|
||||
// 用于分组的批次ID
|
||||
private String batchId; // 批次ID,用于标识同一批次创建的预约时段
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
package org.dromara.xljk.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class XljkConsultationScheduleVo {
|
||||
private Long id;
|
||||
private String tenantId;
|
||||
private Long createDept;
|
||||
private Long createBy;
|
||||
private Date createTime;
|
||||
private Long updateBy;
|
||||
private Date updateTime;
|
||||
private Integer deleted;
|
||||
private Long counselorId;
|
||||
private String counselorName; // 咨询师姓名,用于前端显示
|
||||
private Date scheduleDate;
|
||||
private String timeSlot; // 0上午 1下午
|
||||
private String startTime; // 开始时间 HH:mm 格式
|
||||
private String endTime; // 结束时间 HH:mm 格式
|
||||
private String status;
|
||||
|
||||
// 保留这些字段是为了兼容旧代码,但不再使用
|
||||
private Integer morningEnabled;
|
||||
private Date morningStartTime;
|
||||
private Date morningEndTime;
|
||||
private Integer afternoonEnabled;
|
||||
private Date afternoonStartTime;
|
||||
private Date afternoonEndTime;
|
||||
private Integer maxAppointments;
|
||||
private Integer currentAppointments;
|
||||
}
|
||||
+4
-7
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.dromara.xljk.domain.XljkEvaluationDetail;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
@@ -30,19 +31,16 @@ public class XljkEvaluationDetailVo implements Serializable {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 测评表ID
|
||||
*/
|
||||
@ExcelProperty(value = "测评表ID")
|
||||
private Long evaluationId;
|
||||
|
||||
/**
|
||||
* 学生ID
|
||||
*/
|
||||
@ExcelProperty(value = "学生ID")
|
||||
private Long studentId;
|
||||
|
||||
/**
|
||||
@@ -60,14 +58,14 @@ public class XljkEvaluationDetailVo implements Serializable {
|
||||
/**
|
||||
* 性别(0-男,1-女,2-未知)
|
||||
*/
|
||||
@ExcelProperty(value = "性别", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "sys_user_sex")
|
||||
@ExcelProperty(value = "性别")
|
||||
private String gender;
|
||||
|
||||
/**
|
||||
* 出生日期
|
||||
*/
|
||||
@ExcelProperty(value = "出生日期")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date birthDate;
|
||||
|
||||
@@ -80,8 +78,7 @@ public class XljkEvaluationDetailVo implements Serializable {
|
||||
/**
|
||||
* 心理状态(1-健康,2-良好,3-重点关注)
|
||||
*/
|
||||
@ExcelProperty(value = "心理状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "xljk_mental_status")
|
||||
@ExcelProperty(value = "心理状态")
|
||||
private String mentalStatus;
|
||||
|
||||
/**
|
||||
|
||||
+3
-7
@@ -30,13 +30,11 @@ public class XljkEvaluationVo implements Serializable {
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@ExcelProperty(value = "主键ID")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 院系ID
|
||||
*/
|
||||
@ExcelProperty(value = "院系ID")
|
||||
private Long departmentId;
|
||||
|
||||
/**
|
||||
@@ -54,7 +52,6 @@ public class XljkEvaluationVo implements Serializable {
|
||||
/**
|
||||
* 专业ID
|
||||
*/
|
||||
@ExcelProperty(value = "专业ID")
|
||||
private Long majorId;
|
||||
|
||||
/**
|
||||
@@ -66,7 +63,6 @@ public class XljkEvaluationVo implements Serializable {
|
||||
/**
|
||||
* 班级ID
|
||||
*/
|
||||
@ExcelProperty(value = "班级ID")
|
||||
private Long classId;
|
||||
|
||||
/**
|
||||
@@ -85,7 +81,7 @@ public class XljkEvaluationVo implements Serializable {
|
||||
* 状态(0-草稿,1-已发布,2-已完成)
|
||||
*/
|
||||
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "xljk_evaluation_status")
|
||||
@ExcelDictFormat(dictType = "evaluation_status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
@@ -103,13 +99,13 @@ public class XljkEvaluationVo implements Serializable {
|
||||
/**
|
||||
* 学生数量(非数据库字段)
|
||||
*/
|
||||
@ExcelProperty(value = "学生数量")
|
||||
@ExcelProperty(value = "学生人数")
|
||||
private Integer studentCount;
|
||||
|
||||
/**
|
||||
* 重点关注数量(非数据库字段)
|
||||
*/
|
||||
@ExcelProperty(value = "重点关注数量")
|
||||
@ExcelProperty(value = "重点关注人数")
|
||||
private Integer focusCount;
|
||||
|
||||
/**
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.dromara.xljk.mapper;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationAppointment;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface XljkConsultationAppointmentMapper extends BaseMapper<XljkConsultationAppointment> {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.dromara.xljk.mapper;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationCounselor;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface XljkConsultationCounselorMapper extends BaseMapper<XljkConsultationCounselor> {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.dromara.xljk.mapper;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationNoShow;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface XljkConsultationNoShowMapper extends BaseMapper<XljkConsultationNoShow> {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.dromara.xljk.mapper;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationRecord;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface XljkConsultationRecordMapper extends BaseMapper<XljkConsultationRecord> {
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package org.dromara.xljk.mapper;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationSchedule;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
public interface XljkConsultationScheduleMapper extends BaseMapper<XljkConsultationSchedule> {
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
package org.dromara.xljk.service;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationAppointment;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationAppointmentBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationAppointmentVo;
|
||||
import org.dromara.xljk.domain.vo.TimeSlotDetailVo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 心理咨询预约管理服务接口
|
||||
*
|
||||
* @author Cursor AI
|
||||
*/
|
||||
public interface IXljkConsultationAppointmentService {
|
||||
|
||||
/**
|
||||
* 分页查询预约记录列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
TableDataInfo<XljkConsultationAppointmentVo> selectPageList(XljkConsultationAppointmentBo bo, PageQuery pageQuery);
|
||||
|
||||
XljkConsultationAppointmentVo selectById(Long id);
|
||||
List<XljkConsultationAppointmentVo> selectList(XljkConsultationAppointmentBo bo);
|
||||
boolean insert(XljkConsultationAppointmentBo bo);
|
||||
boolean update(XljkConsultationAppointmentBo bo);
|
||||
boolean deleteById(Long id);
|
||||
|
||||
/**
|
||||
* 获取可预约时段列表(用于日历视图)
|
||||
* @param startDate 开始日期
|
||||
* @param endDate 结束日期
|
||||
* @return 可预约时段列表
|
||||
*/
|
||||
List<Map<String, Object>> getAvailableTimeSlots(Date startDate, Date endDate);
|
||||
|
||||
/**
|
||||
* 获取可用的详细时段列表(30分钟一个时段)
|
||||
* @param date 日期
|
||||
* @param timeSlot 时段类型(0上午 1下午)
|
||||
* @return 详细时段列表
|
||||
*/
|
||||
List<TimeSlotDetailVo> getAvailableDetailSlots(Date date, String timeSlot);
|
||||
|
||||
/**
|
||||
* 学生提交预约
|
||||
* @param bo 预约信息
|
||||
* @return 是否成功
|
||||
*/
|
||||
boolean submitAppointment(XljkConsultationAppointmentBo bo);
|
||||
|
||||
/**
|
||||
* 获取我的预约记录(学生用)
|
||||
* @param studentId 学生ID
|
||||
* @return 预约记录列表
|
||||
*/
|
||||
List<XljkConsultationAppointmentVo> getMyAppointments(Long studentId);
|
||||
|
||||
/**
|
||||
* 记录咨询结果
|
||||
* @param id 预约ID
|
||||
* @param actualVisitTime 实际到访时间
|
||||
* @param communicationDuration 沟通时长
|
||||
* @param consultationContent 咨询内容
|
||||
* @param counselorSuggestion 咨询师建议
|
||||
* @param status 状态(1已完成/3未到访)
|
||||
* @return 是否成功
|
||||
*/
|
||||
boolean recordConsultation(Long id, Date actualVisitTime, Integer communicationDuration,
|
||||
String consultationContent, String counselorSuggestion, String status);
|
||||
|
||||
/**
|
||||
* 获取院系选项
|
||||
* @return 院系选项列表
|
||||
*/
|
||||
List<Map<String, Object>> getCollegeOptions();
|
||||
|
||||
/**
|
||||
* 获取专业选项
|
||||
* @param collegeName 院系名称,可为空
|
||||
* @return 专业选项列表
|
||||
*/
|
||||
List<Map<String, Object>> getMajorOptions(String collegeName);
|
||||
|
||||
/**
|
||||
* 获取班级选项
|
||||
* @param collegeName 院系名称,可为空
|
||||
* @param majorName 专业名称,可为空
|
||||
* @return 班级选项列表
|
||||
*/
|
||||
List<Map<String, Object>> getClassOptions(String collegeName, String majorName);
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.dromara.xljk.service;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationCounselor;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationCounselorBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationCounselorVo;
|
||||
import java.util.List;
|
||||
|
||||
public interface IXljkConsultationCounselorService {
|
||||
XljkConsultationCounselorVo selectById(Long id);
|
||||
List<XljkConsultationCounselorVo> selectList(XljkConsultationCounselorBo bo);
|
||||
boolean insert(XljkConsultationCounselorBo bo);
|
||||
boolean update(XljkConsultationCounselorBo bo);
|
||||
boolean deleteById(Long id);
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.dromara.xljk.service;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationNoShow;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationNoShowBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationNoShowVo;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface IXljkConsultationNoShowService {
|
||||
XljkConsultationNoShowVo selectById(Long id);
|
||||
List<XljkConsultationNoShowVo> selectList(XljkConsultationNoShowBo bo);
|
||||
boolean insert(XljkConsultationNoShowBo bo);
|
||||
boolean update(XljkConsultationNoShowBo bo);
|
||||
boolean deleteById(Long id);
|
||||
|
||||
/**
|
||||
* 检查学生是否被限制预约
|
||||
* @param studentId 学生ID
|
||||
* @return 限制状态信息,包含是否被限制、到期日期等
|
||||
*/
|
||||
Map<String, Object> checkLimitation(Long studentId);
|
||||
|
||||
/**
|
||||
* 解除预约限制
|
||||
* @param id 未到访记录ID
|
||||
* @return 操作结果
|
||||
*/
|
||||
boolean releaseLimitation(Long id);
|
||||
|
||||
/**
|
||||
* 创建未到访记录并检查限制条件
|
||||
* @param studentId 学生ID
|
||||
* @param appointmentId 预约记录ID
|
||||
* @param noShowDate 未到访日期
|
||||
* @return 操作结果
|
||||
*/
|
||||
boolean createNoShowRecord(Long studentId, Long appointmentId, java.util.Date noShowDate);
|
||||
|
||||
/**
|
||||
* 更新过期的限制状态
|
||||
* @return 更新的记录数
|
||||
*/
|
||||
int updateExpiredLimitations();
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package org.dromara.xljk.service;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationRecord;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationRecordBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationRecordVo;
|
||||
import java.util.List;
|
||||
|
||||
public interface IXljkConsultationRecordService {
|
||||
XljkConsultationRecordVo selectById(Long id);
|
||||
List<XljkConsultationRecordVo> selectList(XljkConsultationRecordBo bo);
|
||||
boolean insert(XljkConsultationRecordBo bo);
|
||||
boolean update(XljkConsultationRecordBo bo);
|
||||
boolean deleteById(Long id);
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package org.dromara.xljk.service;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationSchedule;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationScheduleBo;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationScheduleBatchBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationScheduleVo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationScheduleSummaryVo;
|
||||
import java.util.List;
|
||||
|
||||
public interface IXljkConsultationScheduleService {
|
||||
XljkConsultationScheduleVo selectById(Long id);
|
||||
List<XljkConsultationScheduleVo> selectList(XljkConsultationScheduleBo bo);
|
||||
boolean insert(XljkConsultationScheduleBo bo);
|
||||
boolean update(XljkConsultationScheduleBo bo);
|
||||
boolean deleteById(Long id);
|
||||
|
||||
/**
|
||||
* 批量创建预约时段
|
||||
*
|
||||
* @param batchBo 批量创建参数
|
||||
* @return 创建的记录数
|
||||
*/
|
||||
int batchInsert(XljkConsultationScheduleBatchBo batchBo);
|
||||
|
||||
/**
|
||||
* 查询预约时段汇总列表
|
||||
*
|
||||
* @param bo 查询参数
|
||||
* @return 汇总列表
|
||||
*/
|
||||
List<XljkConsultationScheduleSummaryVo> selectSummaryList(XljkConsultationScheduleBo bo);
|
||||
}
|
||||
+8
@@ -4,6 +4,7 @@ import org.dromara.xljk.domain.vo.XljkEvaluationVo;
|
||||
import org.dromara.xljk.domain.bo.XljkEvaluationBo;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.xljk.mapper.XljkEvaluationDetailMapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@@ -17,6 +18,13 @@ import java.util.Map;
|
||||
*/
|
||||
public interface IXljkEvaluationService {
|
||||
|
||||
/**
|
||||
* 获取XljkEvaluationDetailMapper
|
||||
*
|
||||
* @return XljkEvaluationDetailMapper
|
||||
*/
|
||||
XljkEvaluationDetailMapper getDetailMapper();
|
||||
|
||||
/**
|
||||
* 查询心理健康测评
|
||||
*
|
||||
|
||||
+1491
File diff suppressed because it is too large.
Load diff
+58
@@ -0,0 +1,58 @@
|
||||
package org.dromara.xljk.service.impl;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationCounselor;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationCounselorBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationCounselorVo;
|
||||
import org.dromara.xljk.mapper.XljkConsultationCounselorMapper;
|
||||
import org.dromara.xljk.service.IXljkConsultationCounselorService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class XljkConsultationCounselorServiceImpl implements IXljkConsultationCounselorService {
|
||||
@Autowired
|
||||
private XljkConsultationCounselorMapper mapper;
|
||||
|
||||
@Override
|
||||
public XljkConsultationCounselorVo selectById(Long id) {
|
||||
XljkConsultationCounselor entity = mapper.selectById(id);
|
||||
if (entity == null) return null;
|
||||
XljkConsultationCounselorVo vo = new XljkConsultationCounselorVo();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XljkConsultationCounselorVo> selectList(XljkConsultationCounselorBo bo) {
|
||||
// 简单实现:全表查找,可根据bo补充条件
|
||||
List<XljkConsultationCounselor> list = mapper.selectList(null);
|
||||
return list.stream().map(entity -> {
|
||||
XljkConsultationCounselorVo vo = new XljkConsultationCounselorVo();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(XljkConsultationCounselorBo bo) {
|
||||
XljkConsultationCounselor entity = new XljkConsultationCounselor();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
return mapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(XljkConsultationCounselorBo bo) {
|
||||
XljkConsultationCounselor entity = new XljkConsultationCounselor();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
return mapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteById(Long id) {
|
||||
return mapper.deleteById(id) > 0;
|
||||
}
|
||||
}
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
package org.dromara.xljk.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.dromara.xljk.domain.XljkConsultationNoShow;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationNoShowBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationNoShowVo;
|
||||
import org.dromara.xljk.mapper.XljkConsultationNoShowMapper;
|
||||
import org.dromara.xljk.service.IXljkConsultationNoShowService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class XljkConsultationNoShowServiceImpl implements IXljkConsultationNoShowService {
|
||||
@Autowired
|
||||
private XljkConsultationNoShowMapper mapper;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Override
|
||||
public XljkConsultationNoShowVo selectById(Long id) {
|
||||
// 使用JOIN查询获取更多详细信息
|
||||
StringBuilder sqlBuilder = new StringBuilder();
|
||||
sqlBuilder.append("SELECT ns.*, ");
|
||||
sqlBuilder.append("s.name as student_name, s.student_no, s.class_name, s.college_name, s.major_name, ");
|
||||
sqlBuilder.append("a.appointment_date, a.appointment_detail_time, a.reason, a.counselor_id, ");
|
||||
sqlBuilder.append("u.nick_name as counselor_name ");
|
||||
sqlBuilder.append("FROM xljk_consultation_no_show ns ");
|
||||
sqlBuilder.append("LEFT JOIN xg_student_msg s ON ns.student_id = s.id ");
|
||||
sqlBuilder.append("LEFT JOIN xljk_consultation_appointment a ON ns.appointment_id = a.id ");
|
||||
sqlBuilder.append("LEFT JOIN sys_user u ON a.counselor_id = u.user_id ");
|
||||
sqlBuilder.append("WHERE ns.id = ? AND ns.deleted = 0");
|
||||
|
||||
List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sqlBuilder.toString(), id);
|
||||
|
||||
if (resultList.isEmpty()) return null;
|
||||
|
||||
Map<String, Object> row = resultList.get(0);
|
||||
XljkConsultationNoShowVo vo = new XljkConsultationNoShowVo();
|
||||
|
||||
// 设置基本字段
|
||||
vo.setId(((Number) row.get("id")).longValue());
|
||||
vo.setStudentId(row.get("student_id") != null ? ((Number) row.get("student_id")).longValue() : null);
|
||||
vo.setAppointmentId(row.get("appointment_id") != null ? ((Number) row.get("appointment_id")).longValue() : null);
|
||||
vo.setNoShowDate(convertToDate(row.get("no_show_date")));
|
||||
vo.setExpireDate(convertToDate(row.get("expire_date")));
|
||||
vo.setStatus((String) row.get("status"));
|
||||
vo.setCreateTime(convertToDate(row.get("create_time")));
|
||||
vo.setUpdateTime(convertToDate(row.get("update_time")));
|
||||
|
||||
// 设置学生相关信息
|
||||
vo.setStudentName((String) row.get("student_name"));
|
||||
vo.setStudentNo((String) row.get("student_no"));
|
||||
vo.setClassName((String) row.get("class_name"));
|
||||
vo.setCollegeName((String) row.get("college_name"));
|
||||
vo.setMajorName((String) row.get("major_name"));
|
||||
|
||||
// 设置预约相关信息
|
||||
vo.setCounselorName((String) row.get("counselor_name")); // 从counselor表获取咨询师姓名
|
||||
vo.setAppointmentDate(convertToDate(row.get("appointment_date")));
|
||||
vo.setAppointmentDetailTime((String) row.get("appointment_detail_time"));
|
||||
vo.setReason((String) row.get("reason"));
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XljkConsultationNoShowVo> selectList(XljkConsultationNoShowBo bo) {
|
||||
// 构建基础SQL查询
|
||||
StringBuilder sqlBuilder = new StringBuilder();
|
||||
sqlBuilder.append("SELECT ns.*, ");
|
||||
sqlBuilder.append("s.name as student_name, s.student_no, s.class_name, s.college_name, s.major_name ");
|
||||
sqlBuilder.append("FROM xljk_consultation_no_show ns ");
|
||||
sqlBuilder.append("LEFT JOIN xg_student_msg s ON ns.student_id = s.id ");
|
||||
sqlBuilder.append("WHERE ns.deleted = 0 ");
|
||||
|
||||
List<Object> params = new ArrayList<>();
|
||||
|
||||
// 添加查询条件
|
||||
if (bo.getStudentId() != null) {
|
||||
sqlBuilder.append("AND ns.student_id = ? ");
|
||||
params.add(bo.getStudentId());
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(bo.getStudentName())) {
|
||||
sqlBuilder.append("AND s.name LIKE ? ");
|
||||
params.add("%" + bo.getStudentName() + "%");
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(bo.getStudentNo())) {
|
||||
sqlBuilder.append("AND s.student_no LIKE ? ");
|
||||
params.add("%" + bo.getStudentNo() + "%");
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(bo.getStatus())) {
|
||||
sqlBuilder.append("AND ns.status = ? ");
|
||||
params.add(bo.getStatus());
|
||||
}
|
||||
|
||||
// 处理日期范围
|
||||
if (bo.getParams() != null) {
|
||||
Object startDateObj = bo.getParams().get("startDate");
|
||||
if (startDateObj != null && StringUtils.isNotBlank(startDateObj.toString())) {
|
||||
sqlBuilder.append("AND DATE(ns.no_show_date) >= DATE(?) ");
|
||||
params.add(startDateObj.toString());
|
||||
log.info("添加开始日期查询条件: {}", startDateObj);
|
||||
}
|
||||
|
||||
Object endDateObj = bo.getParams().get("endDate");
|
||||
if (endDateObj != null && StringUtils.isNotBlank(endDateObj.toString())) {
|
||||
sqlBuilder.append("AND DATE(ns.no_show_date) <= DATE(?) ");
|
||||
params.add(endDateObj.toString());
|
||||
log.info("添加结束日期查询条件: {}", endDateObj);
|
||||
}
|
||||
}
|
||||
|
||||
// 添加排序,首先按未到访日期倒序,其次按创建时间倒序
|
||||
sqlBuilder.append("ORDER BY ns.no_show_date DESC, ns.create_time DESC");
|
||||
|
||||
// 执行查询
|
||||
List<Map<String, Object>> resultList = jdbcTemplate.queryForList(sqlBuilder.toString(), params.toArray());
|
||||
|
||||
// 转换为VO对象
|
||||
return resultList.stream().map(row -> {
|
||||
XljkConsultationNoShowVo vo = new XljkConsultationNoShowVo();
|
||||
|
||||
// 设置基本字段
|
||||
vo.setId(((Number) row.get("id")).longValue());
|
||||
vo.setStudentId(row.get("student_id") != null ? ((Number) row.get("student_id")).longValue() : null);
|
||||
vo.setAppointmentId(row.get("appointment_id") != null ? ((Number) row.get("appointment_id")).longValue() : null);
|
||||
vo.setNoShowDate(convertToDate(row.get("no_show_date")));
|
||||
vo.setExpireDate(convertToDate(row.get("expire_date")));
|
||||
vo.setStatus((String) row.get("status"));
|
||||
vo.setCreateTime(convertToDate(row.get("create_time")));
|
||||
vo.setUpdateTime(convertToDate(row.get("update_time")));
|
||||
|
||||
// 设置关联信息
|
||||
vo.setStudentName((String) row.get("student_name"));
|
||||
vo.setStudentNo((String) row.get("student_no"));
|
||||
vo.setClassName((String) row.get("class_name"));
|
||||
vo.setCollegeName((String) row.get("college_name"));
|
||||
vo.setMajorName((String) row.get("major_name"));
|
||||
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(XljkConsultationNoShowBo bo) {
|
||||
XljkConsultationNoShow entity = new XljkConsultationNoShow();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
return mapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(XljkConsultationNoShowBo bo) {
|
||||
XljkConsultationNoShow entity = new XljkConsultationNoShow();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
return mapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteById(Long id) {
|
||||
return mapper.deleteById(id) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> checkLimitation(Long studentId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("limited", false);
|
||||
|
||||
try {
|
||||
// 查询是否有生效中的限制
|
||||
LambdaQueryWrapper<XljkConsultationNoShow> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(XljkConsultationNoShow::getStudentId, studentId)
|
||||
.eq(XljkConsultationNoShow::getStatus, "0") // 0-生效中
|
||||
.eq(XljkConsultationNoShow::getDeleted, 0)
|
||||
.orderByDesc(XljkConsultationNoShow::getCreateTime);
|
||||
|
||||
XljkConsultationNoShow noShow = mapper.selectOne(queryWrapper);
|
||||
|
||||
if (noShow != null) {
|
||||
Date now = new Date();
|
||||
Date expireDate = noShow.getExpireDate();
|
||||
|
||||
// 如果限制已过期,更新状态
|
||||
if (expireDate != null && now.after(expireDate)) {
|
||||
log.info("学生{}的预约限制已过期,自动更新状态", studentId);
|
||||
noShow.setStatus("1"); // 1-已过期
|
||||
mapper.updateById(noShow);
|
||||
} else {
|
||||
// 限制仍在生效期内
|
||||
result.put("limited", true);
|
||||
result.put("expireDate", expireDate);
|
||||
|
||||
// 格式化日期为字符串
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
result.put("expireDateStr", sdf.format(expireDate));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("检查预约限制失败", e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean releaseLimitation(Long id) {
|
||||
try {
|
||||
XljkConsultationNoShow noShow = mapper.selectById(id);
|
||||
if (noShow == null) {
|
||||
log.warn("未找到ID为{}的未到访记录", id);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 只有生效中的限制才能解除
|
||||
if ("0".equals(noShow.getStatus())) {
|
||||
noShow.setStatus("2"); // 2-已解除
|
||||
mapper.updateById(noShow);
|
||||
log.info("成功解除学生{}的预约限制", noShow.getStudentId());
|
||||
return true;
|
||||
} else {
|
||||
log.warn("未到访记录{}不是生效中状态,无需解除", id);
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解除预约限制失败", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean createNoShowRecord(Long studentId, Long appointmentId, Date noShowDate) {
|
||||
try {
|
||||
// 创建未到访记录
|
||||
XljkConsultationNoShow noShow = new XljkConsultationNoShow();
|
||||
noShow.setStudentId(studentId);
|
||||
noShow.setAppointmentId(appointmentId);
|
||||
noShow.setNoShowDate(noShowDate);
|
||||
|
||||
// 检查30天内未到访次数
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -30);
|
||||
Date thirtyDaysAgo = calendar.getTime();
|
||||
|
||||
LambdaQueryWrapper<XljkConsultationNoShow> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(XljkConsultationNoShow::getStudentId, studentId)
|
||||
.ge(XljkConsultationNoShow::getNoShowDate, thirtyDaysAgo)
|
||||
.eq(XljkConsultationNoShow::getDeleted, 0);
|
||||
|
||||
long count = mapper.selectCount(queryWrapper);
|
||||
log.info("学生{}在30天内未到访次数: {}", studentId, count);
|
||||
|
||||
// 如果达到3次,设置限制(包括本次)
|
||||
if (count >= 2) { // 已有2次,加上本次就是3次
|
||||
log.info("学生{}达到3次未到访,设置预约限制", studentId);
|
||||
// 计算限制到期日(7天后)
|
||||
calendar = Calendar.getInstance();
|
||||
calendar.setTime(noShowDate);
|
||||
calendar.add(Calendar.DAY_OF_MONTH, 7);
|
||||
Date expireDate = calendar.getTime();
|
||||
|
||||
noShow.setExpireDate(expireDate);
|
||||
noShow.setStatus("0"); // 0-生效中
|
||||
}
|
||||
|
||||
// 保存未到访记录
|
||||
mapper.insert(noShow);
|
||||
log.info("创建未到访记录成功: {}", noShow);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("创建未到访记录失败", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateExpiredLimitations() {
|
||||
log.info("开始检查过期的预约限制");
|
||||
int count = 0;
|
||||
|
||||
try {
|
||||
Date now = new Date();
|
||||
|
||||
// 查询所有生效中但已过期的限制
|
||||
LambdaQueryWrapper<XljkConsultationNoShow> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(XljkConsultationNoShow::getStatus, "0") // 0-生效中
|
||||
.lt(XljkConsultationNoShow::getExpireDate, now) // 过期日期早于当前日期
|
||||
.eq(XljkConsultationNoShow::getDeleted, 0);
|
||||
|
||||
List<XljkConsultationNoShow> expiredList = mapper.selectList(queryWrapper);
|
||||
log.info("找到{}条已过期的预约限制", expiredList.size());
|
||||
|
||||
// 批量更新状态为已过期
|
||||
for (XljkConsultationNoShow noShow : expiredList) {
|
||||
noShow.setStatus("1"); // 1-已过期
|
||||
mapper.updateById(noShow);
|
||||
log.info("更新学生{}的预约限制为已过期", noShow.getStudentId());
|
||||
count++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("更新过期预约限制失败", e);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将各种日期类型转换为java.util.Date
|
||||
*
|
||||
* @param dateObj 日期对象,可能是LocalDateTime、LocalDate、Date或其他类型
|
||||
* @return java.util.Date对象,如果转换失败则返回null
|
||||
*/
|
||||
private Date convertToDate(Object dateObj) {
|
||||
if (dateObj == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (dateObj instanceof Date) {
|
||||
return (Date) dateObj;
|
||||
} else if (dateObj instanceof LocalDateTime) {
|
||||
LocalDateTime localDateTime = (LocalDateTime) dateObj;
|
||||
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
|
||||
} else if (dateObj instanceof LocalDate) {
|
||||
LocalDate localDate = (LocalDate) dateObj;
|
||||
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
} else if (dateObj instanceof java.sql.Date) {
|
||||
return new Date(((java.sql.Date) dateObj).getTime());
|
||||
} else if (dateObj instanceof java.sql.Timestamp) {
|
||||
return new Date(((java.sql.Timestamp) dateObj).getTime());
|
||||
} else {
|
||||
log.warn("未知的日期类型: {}", dateObj.getClass().getName());
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("日期转换错误: {}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package org.dromara.xljk.service.impl;
|
||||
|
||||
import org.dromara.xljk.domain.XljkConsultationRecord;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationRecordBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationRecordVo;
|
||||
import org.dromara.xljk.mapper.XljkConsultationRecordMapper;
|
||||
import org.dromara.xljk.service.IXljkConsultationRecordService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class XljkConsultationRecordServiceImpl implements IXljkConsultationRecordService {
|
||||
@Autowired
|
||||
private XljkConsultationRecordMapper mapper;
|
||||
|
||||
@Override
|
||||
public XljkConsultationRecordVo selectById(Long id) {
|
||||
XljkConsultationRecord entity = mapper.selectById(id);
|
||||
if (entity == null) return null;
|
||||
XljkConsultationRecordVo vo = new XljkConsultationRecordVo();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XljkConsultationRecordVo> selectList(XljkConsultationRecordBo bo) {
|
||||
List<XljkConsultationRecord> list = mapper.selectList(null);
|
||||
return list.stream().map(entity -> {
|
||||
XljkConsultationRecordVo vo = new XljkConsultationRecordVo();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(XljkConsultationRecordBo bo) {
|
||||
XljkConsultationRecord entity = new XljkConsultationRecord();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
return mapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(XljkConsultationRecordBo bo) {
|
||||
XljkConsultationRecord entity = new XljkConsultationRecord();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
return mapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteById(Long id) {
|
||||
return mapper.deleteById(id) > 0;
|
||||
}
|
||||
}
|
||||
+350
@@ -0,0 +1,350 @@
|
||||
package org.dromara.xljk.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.dromara.xljk.domain.XljkConsultationSchedule;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationScheduleBo;
|
||||
import org.dromara.xljk.domain.bo.XljkConsultationScheduleBatchBo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationScheduleVo;
|
||||
import org.dromara.xljk.domain.vo.XljkConsultationScheduleSummaryVo;
|
||||
import org.dromara.xljk.mapper.XljkConsultationScheduleMapper;
|
||||
import org.dromara.xljk.service.IXljkConsultationScheduleService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class XljkConsultationScheduleServiceImpl implements IXljkConsultationScheduleService {
|
||||
@Autowired
|
||||
private XljkConsultationScheduleMapper mapper;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Override
|
||||
public XljkConsultationScheduleVo selectById(Long id) {
|
||||
XljkConsultationSchedule entity = mapper.selectById(id);
|
||||
if (entity == null) return null;
|
||||
XljkConsultationScheduleVo vo = new XljkConsultationScheduleVo();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
// 查询咨询师姓名
|
||||
if (entity.getCounselorId() != null) {
|
||||
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, entity.getCounselorId());
|
||||
if (!result.isEmpty()) {
|
||||
vo.setCounselorName((String) result.get(0).get("nick_name"));
|
||||
}
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XljkConsultationScheduleVo> selectList(XljkConsultationScheduleBo bo) {
|
||||
LambdaQueryWrapper<XljkConsultationSchedule> queryWrapper = new LambdaQueryWrapper<>();
|
||||
// 可以添加查询条件
|
||||
if (bo.getCounselorId() != null) {
|
||||
queryWrapper.eq(XljkConsultationSchedule::getCounselorId, bo.getCounselorId());
|
||||
}
|
||||
List<XljkConsultationSchedule> list = mapper.selectList(queryWrapper);
|
||||
return list.stream().map(entity -> {
|
||||
XljkConsultationScheduleVo vo = new XljkConsultationScheduleVo();
|
||||
BeanUtils.copyProperties(entity, vo);
|
||||
// 查询咨询师姓名
|
||||
if (entity.getCounselorId() != null) {
|
||||
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, entity.getCounselorId());
|
||||
if (!result.isEmpty()) {
|
||||
vo.setCounselorName((String) result.get(0).get("nick_name"));
|
||||
}
|
||||
}
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XljkConsultationScheduleSummaryVo> selectSummaryList(XljkConsultationScheduleBo bo) {
|
||||
// 查询所有符合条件的预约时段
|
||||
LambdaQueryWrapper<XljkConsultationSchedule> queryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
// 添加查询条件
|
||||
if (bo.getCounselorId() != null) {
|
||||
queryWrapper.eq(XljkConsultationSchedule::getCounselorId, bo.getCounselorId());
|
||||
}
|
||||
|
||||
// 按批次ID分组,获取所有不同的批次
|
||||
queryWrapper.groupBy(XljkConsultationSchedule::getBatchId);
|
||||
queryWrapper.orderByDesc(XljkConsultationSchedule::getCreateTime);
|
||||
|
||||
List<XljkConsultationSchedule> batchGroups = mapper.selectList(queryWrapper);
|
||||
|
||||
// 创建汇总列表
|
||||
List<XljkConsultationScheduleSummaryVo> summaryList = new ArrayList<>();
|
||||
|
||||
// 处理每个批次
|
||||
for (XljkConsultationSchedule batchGroup : batchGroups) {
|
||||
String batchId = batchGroup.getBatchId();
|
||||
|
||||
// 如果批次ID为空,则这是单独创建的预约时段,直接添加到列表中
|
||||
if (batchId == null || batchId.isEmpty()) {
|
||||
XljkConsultationScheduleSummaryVo summary = new XljkConsultationScheduleSummaryVo();
|
||||
BeanUtils.copyProperties(batchGroup, summary);
|
||||
|
||||
// 设置日期范围
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
if (batchGroup.getScheduleDate() != null) {
|
||||
summary.setDateRange(dateFormat.format(batchGroup.getScheduleDate()));
|
||||
} else {
|
||||
summary.setDateRange("未设置");
|
||||
}
|
||||
|
||||
// 设置时段信息
|
||||
if ("0".equals(batchGroup.getTimeSlot())) {
|
||||
summary.setMorningEnabled(true);
|
||||
summary.setMorningTime(batchGroup.getStartTime() + "-" + batchGroup.getEndTime());
|
||||
summary.setAfternoonEnabled(false);
|
||||
} else {
|
||||
summary.setMorningEnabled(false);
|
||||
summary.setAfternoonEnabled(true);
|
||||
summary.setAfternoonTime(batchGroup.getStartTime() + "-" + batchGroup.getEndTime());
|
||||
}
|
||||
|
||||
// 设置数量
|
||||
summary.setScheduleCount(1);
|
||||
|
||||
// 查询咨询师姓名
|
||||
if (batchGroup.getCounselorId() != null) {
|
||||
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, batchGroup.getCounselorId());
|
||||
if (!result.isEmpty()) {
|
||||
summary.setCounselorName((String) result.get(0).get("nick_name"));
|
||||
}
|
||||
}
|
||||
|
||||
// 确保创建时间不为空
|
||||
if (summary.getCreateTime() == null) {
|
||||
summary.setCreateTime(new Date());
|
||||
}
|
||||
|
||||
summaryList.add(summary);
|
||||
} else {
|
||||
// 查询该批次的所有预约时段
|
||||
LambdaQueryWrapper<XljkConsultationSchedule> batchQueryWrapper = new LambdaQueryWrapper<>();
|
||||
batchQueryWrapper.eq(XljkConsultationSchedule::getBatchId, batchId);
|
||||
batchQueryWrapper.orderByAsc(XljkConsultationSchedule::getScheduleDate);
|
||||
List<XljkConsultationSchedule> batchSchedules = mapper.selectList(batchQueryWrapper);
|
||||
|
||||
if (!batchSchedules.isEmpty()) {
|
||||
XljkConsultationScheduleSummaryVo summary = new XljkConsultationScheduleSummaryVo();
|
||||
|
||||
// 设置基本信息
|
||||
XljkConsultationSchedule firstSchedule = batchSchedules.get(0);
|
||||
XljkConsultationSchedule lastSchedule = batchSchedules.get(batchSchedules.size() - 1);
|
||||
|
||||
summary.setId(firstSchedule.getId());
|
||||
summary.setTenantId(firstSchedule.getTenantId());
|
||||
summary.setCreateDept(firstSchedule.getCreateDept());
|
||||
summary.setCreateBy(firstSchedule.getCreateBy());
|
||||
|
||||
// 设置创建时间,如果为空则使用当前时间
|
||||
if (firstSchedule.getCreateTime() != null) {
|
||||
summary.setCreateTime(firstSchedule.getCreateTime());
|
||||
} else {
|
||||
summary.setCreateTime(new Date());
|
||||
}
|
||||
|
||||
summary.setUpdateBy(firstSchedule.getUpdateBy());
|
||||
summary.setUpdateTime(firstSchedule.getUpdateTime());
|
||||
summary.setDeleted(firstSchedule.getDeleted());
|
||||
summary.setCounselorId(firstSchedule.getCounselorId());
|
||||
summary.setStatus(firstSchedule.getStatus());
|
||||
summary.setBatchId(batchId);
|
||||
|
||||
// 设置日期范围
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
if (firstSchedule.getScheduleDate() != null && lastSchedule.getScheduleDate() != null) {
|
||||
summary.setDateRange(dateFormat.format(firstSchedule.getScheduleDate()) +
|
||||
" 至 " +
|
||||
dateFormat.format(lastSchedule.getScheduleDate()));
|
||||
} else {
|
||||
summary.setDateRange("未设置");
|
||||
}
|
||||
|
||||
// 设置时段信息
|
||||
boolean hasMorning = false;
|
||||
boolean hasAfternoon = false;
|
||||
String morningTime = "";
|
||||
String afternoonTime = "";
|
||||
|
||||
for (XljkConsultationSchedule schedule : batchSchedules) {
|
||||
if ("0".equals(schedule.getTimeSlot())) {
|
||||
hasMorning = true;
|
||||
morningTime = schedule.getStartTime() + "-" + schedule.getEndTime();
|
||||
} else if ("1".equals(schedule.getTimeSlot())) {
|
||||
hasAfternoon = true;
|
||||
afternoonTime = schedule.getStartTime() + "-" + schedule.getEndTime();
|
||||
}
|
||||
}
|
||||
|
||||
summary.setMorningEnabled(hasMorning);
|
||||
summary.setMorningTime(morningTime);
|
||||
summary.setAfternoonEnabled(hasAfternoon);
|
||||
summary.setAfternoonTime(afternoonTime);
|
||||
|
||||
// 设置数量
|
||||
summary.setScheduleCount(batchSchedules.size());
|
||||
|
||||
// 查询咨询师姓名
|
||||
if (firstSchedule.getCounselorId() != null) {
|
||||
String sql = "SELECT nick_name FROM sys_user WHERE user_id = ?";
|
||||
List<Map<String, Object>> result = jdbcTemplate.queryForList(sql, firstSchedule.getCounselorId());
|
||||
if (!result.isEmpty()) {
|
||||
summary.setCounselorName((String) result.get(0).get("nick_name"));
|
||||
}
|
||||
}
|
||||
|
||||
summaryList.add(summary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return summaryList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean insert(XljkConsultationScheduleBo bo) {
|
||||
XljkConsultationSchedule entity = new XljkConsultationSchedule();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
|
||||
// 设置创建时间
|
||||
if (entity.getCreateTime() == null) {
|
||||
entity.setCreateTime(new Date());
|
||||
}
|
||||
|
||||
return mapper.insert(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(XljkConsultationScheduleBo bo) {
|
||||
XljkConsultationSchedule entity = new XljkConsultationSchedule();
|
||||
BeanUtils.copyProperties(bo, entity);
|
||||
return mapper.updateById(entity) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteById(Long id) {
|
||||
// 检查是否是批次的一部分
|
||||
XljkConsultationSchedule schedule = mapper.selectById(id);
|
||||
if (schedule != null && schedule.getBatchId() != null && !schedule.getBatchId().isEmpty()) {
|
||||
// 删除整个批次
|
||||
LambdaQueryWrapper<XljkConsultationSchedule> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(XljkConsultationSchedule::getBatchId, schedule.getBatchId());
|
||||
return mapper.delete(queryWrapper) > 0;
|
||||
} else {
|
||||
// 删除单个记录
|
||||
return mapper.deleteById(id) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int batchInsert(XljkConsultationScheduleBatchBo batchBo) {
|
||||
if (batchBo == null || batchBo.getCounselorId() == null ||
|
||||
batchBo.getStartDate() == null || batchBo.getEndDate() == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 检查是否至少启用了一个时段
|
||||
if ((batchBo.getMorningEnabled() == null || !batchBo.getMorningEnabled()) &&
|
||||
(batchBo.getAfternoonEnabled() == null || !batchBo.getAfternoonEnabled())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 生成批次ID
|
||||
String batchId = UUID.randomUUID().toString();
|
||||
batchBo.setBatchId(batchId);
|
||||
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
try {
|
||||
Date startDate = dateFormat.parse(batchBo.getStartDate());
|
||||
Date endDate = dateFormat.parse(batchBo.getEndDate());
|
||||
|
||||
if (startDate.after(endDate)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<XljkConsultationSchedule> schedules = new ArrayList<>();
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(startDate);
|
||||
|
||||
// 获取当前时间作为创建时间
|
||||
Date now = new Date();
|
||||
|
||||
// 循环创建每一天的预约时段
|
||||
while (!calendar.getTime().after(endDate)) {
|
||||
Date currentDate = calendar.getTime();
|
||||
|
||||
// 检查是否为周末
|
||||
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
boolean isWeekend = (dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY);
|
||||
|
||||
// 如果是周末且设置了跳过周末,则跳过
|
||||
if (!(isWeekend && Boolean.TRUE.equals(batchBo.getSkipWeekends()))) {
|
||||
// 创建上午时段
|
||||
if (Boolean.TRUE.equals(batchBo.getMorningEnabled())) {
|
||||
XljkConsultationSchedule morningSchedule = new XljkConsultationSchedule();
|
||||
morningSchedule.setCounselorId(batchBo.getCounselorId());
|
||||
morningSchedule.setScheduleDate(currentDate);
|
||||
morningSchedule.setTimeSlot("0"); // 上午
|
||||
morningSchedule.setStartTime(batchBo.getMorningStartTime());
|
||||
morningSchedule.setEndTime(batchBo.getMorningEndTime());
|
||||
morningSchedule.setStatus(batchBo.getStatus());
|
||||
morningSchedule.setBatchId(batchId); // 设置批次ID
|
||||
morningSchedule.setCreateTime(now); // 设置创建时间
|
||||
schedules.add(morningSchedule);
|
||||
}
|
||||
|
||||
// 创建下午时段
|
||||
if (Boolean.TRUE.equals(batchBo.getAfternoonEnabled())) {
|
||||
XljkConsultationSchedule afternoonSchedule = new XljkConsultationSchedule();
|
||||
afternoonSchedule.setCounselorId(batchBo.getCounselorId());
|
||||
afternoonSchedule.setScheduleDate(currentDate);
|
||||
afternoonSchedule.setTimeSlot("1"); // 下午
|
||||
afternoonSchedule.setStartTime(batchBo.getAfternoonStartTime());
|
||||
afternoonSchedule.setEndTime(batchBo.getAfternoonEndTime());
|
||||
afternoonSchedule.setStatus(batchBo.getStatus());
|
||||
afternoonSchedule.setBatchId(batchId); // 设置批次ID
|
||||
afternoonSchedule.setCreateTime(now); // 设置创建时间
|
||||
schedules.add(afternoonSchedule);
|
||||
}
|
||||
}
|
||||
|
||||
// 增加一天
|
||||
calendar.add(Calendar.DAY_OF_MONTH, 1);
|
||||
}
|
||||
|
||||
// 批量插入数据库
|
||||
for (XljkConsultationSchedule schedule : schedules) {
|
||||
mapper.insert(schedule);
|
||||
}
|
||||
|
||||
return schedules.size();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 249 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user