commit b377c87a1adbbcd1422188e5a1e0483ead59067e Author: wucongxing8150 <815046773@qq.com> Date: Mon Aug 11 10:39:53 2025 +0800 1 diff --git a/sa-admin/pom.xml b/sa-admin/pom.xml new file mode 100644 index 0000000..c5ac192 --- /dev/null +++ b/sa-admin/pom.xml @@ -0,0 +1,47 @@ + + 4.0.0 + + net.lab1024 + sa-parent + 3.0.0 + ../pom.xml + + + sa-admin + 3.0.0 + jar + + sa-admin + sa-admin project + + + + + net.lab1024 + sa-base + 3.0.0 + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + net.lab1024.sa.admin.AdminApplication + + + + + repackage + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/AdminApplication.java b/sa-admin/src/main/java/net/lab1024/sa/admin/AdminApplication.java new file mode 100644 index 0000000..0d4863c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/AdminApplication.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin; + +import net.lab1024.sa.base.listener.Ip2RegionListener; +import net.lab1024.sa.base.listener.LogVariableListener; +import org.apache.ibatis.annotations.Mapper; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * SmartAdmin 项目启动类 + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2022-08-29 21:00:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@EnableCaching +@EnableScheduling +@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) +@ComponentScan(AdminApplication.COMPONENT_SCAN) +@MapperScan(value = AdminApplication.COMPONENT_SCAN, annotationClass = Mapper.class) +@SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class}) +public class AdminApplication { + + public static final String COMPONENT_SCAN = "net.lab1024.sa"; + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(AdminApplication.class); + // 添加 日志监听器,使 log4j2-spring.xml 可以间接读取到配置文件的属性 + application.addListeners(new LogVariableListener(), new Ip2RegionListener()); + application.run(args); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/AppConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/AppConfig.java new file mode 100644 index 0000000..b69644f --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/AppConfig.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.admin.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Data +@Component +public class AppConfig { + + @Value("${app.apiUrl}") + private String apiUrl; + + @Value("${app.secretKey}") + private String secretKey; + + @Value("${app.imagePrefix}") + private String imagePrefix; + + @Value("${app.platform}") + private String platform; + + @Value("${app.platformPointAccount}") + private String platformPointAccount; + + @Value("${app.access-token}") + private String accessToken; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/DySmsConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/DySmsConfig.java new file mode 100644 index 0000000..adcf178 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/DySmsConfig.java @@ -0,0 +1,16 @@ +package net.lab1024.sa.admin.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Data +@Component +public class DySmsConfig { + + @Value("${aliyun.sms.access-key:}") + private String accessKey; + + @Value("${aliyun.sms.access-secret:}") + private String accessSecret; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/EnvConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/EnvConfig.java new file mode 100644 index 0000000..cc0e9d3 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/EnvConfig.java @@ -0,0 +1,13 @@ +package net.lab1024.sa.admin.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Data +@Component +public class EnvConfig { + + @Value("${spring.profiles.active:prod}") + private String active; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/MvcConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/MvcConfig.java new file mode 100644 index 0000000..f5e88a5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/MvcConfig.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.admin.config; + +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.interceptor.AdminInterceptor; +import net.lab1024.sa.base.config.SwaggerConfig; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * web相关配置 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2021-09-02 20:21:10 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Configuration +public class MvcConfig implements WebMvcConfigurer { + + @Resource + private AdminInterceptor adminInterceptor; + + + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(adminInterceptor) + .excludePathPatterns(SwaggerConfig.SWAGGER_WHITELIST) + .addPathPatterns("/**"); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); + registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/MyMetaObjectHandler.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/MyMetaObjectHandler.java new file mode 100644 index 0000000..43da9f8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/MyMetaObjectHandler.java @@ -0,0 +1,25 @@ +package net.lab1024.sa.admin.config; + +import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; +import org.apache.ibatis.reflection.MetaObject; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.ZoneId; + +@Component +public class MyMetaObjectHandler implements MetaObjectHandler { + + private static final ZoneId BEIJING_ZONE = ZoneId.of("Asia/Shanghai"); + + @Override + public void insertFill(MetaObject metaObject) { + this.strictInsertFill(metaObject, "createdAt", LocalDateTime.class, LocalDateTime.now(BEIJING_ZONE)); + this.strictInsertFill(metaObject, "updatedAt", LocalDateTime.class, LocalDateTime.now(BEIJING_ZONE)); + } + + @Override + public void updateFill(MetaObject metaObject) { + this.strictUpdateFill(metaObject, "updatedAt", LocalDateTime.class, LocalDateTime.now()); + } +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/OperateLogAspectConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/OperateLogAspectConfig.java new file mode 100644 index 0000000..bccbfb4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/OperateLogAspectConfig.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.admin.config; + +import net.lab1024.sa.base.module.support.operatelog.core.OperateLogAspect; +import net.lab1024.sa.base.module.support.operatelog.core.OperateLogConfig; +import org.springframework.context.annotation.Configuration; + +/** + * 操作日志切面 配置 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-05-30 21:22:12 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Configuration +public class OperateLogAspectConfig extends OperateLogAspect{ + + /** + * 配置信息 + */ + @Override + public OperateLogConfig getOperateLogConfig() { + return OperateLogConfig.builder().corePoolSize(1).queueCapacity(10000).build(); + } + + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/OssConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/OssConfig.java new file mode 100644 index 0000000..6464fe8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/OssConfig.java @@ -0,0 +1,25 @@ +package net.lab1024.sa.admin.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Data +@Component +public class OssConfig { + + @Value("${file.storage.cloud.endpoint}") + private String endpoint; + + @Value("${file.storage.cloud.access-key}") + private String accessKey; + + @Value("${file.storage.cloud.secret-key}") + private String accessKeySecret; + + @Value("${file.storage.cloud.bucket-name}") + private String bucket; + + @Value("${file.storage.cloud.url-prefix}") + private String customDomainName; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/RedisConfiguration.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/RedisConfiguration.java new file mode 100644 index 0000000..f33ebed --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/RedisConfiguration.java @@ -0,0 +1,73 @@ +package net.lab1024.sa.admin.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisPassword; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; + + +@Configuration +@RequiredArgsConstructor +public class RedisConfiguration { + // 开发环境Redis配置 + @Value("${spring.data.redis.database:0}") + private String database; + + @Value("${spring.data.redis.host:localhost}") + private String host; + + @Value("${spring.data.redis.port:6379}") + private Integer port; + + @Value("${spring.data.redis.password:}") + private String password; + + // 生产环境Redis配置(如果没有配置,使用开发环境配置) + @Value("${spring.data.prod-redis.host:${spring.data.redis.host:localhost}}") + private String prodHost; + + @Value("${spring.data.prod-redis.port:${spring.data.redis.port:6379}}") + private Integer prodPort; + + @Value("${spring.data.prod-redis.database:${spring.data.redis.database:0}}") + private String prodDatabase; + + @Value("${spring.data.prod-redis.password:${spring.data.redis.password:}}") + private String prodPassword; + + // 移除redisTemplate的定义,使用框架自带的 + + @Bean + @Qualifier("prodRedisTemplate") + public RedisTemplate prodRedisTemplate(RedisConnectionFactory connectionFactory) { + RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(); + configuration.setHostName(prodHost); + configuration.setPort(prodPort); + configuration.setDatabase(Integer.parseInt(prodDatabase)); + if (prodPassword != null && !prodPassword.isEmpty()) { + configuration.setPassword(RedisPassword.of(prodPassword)); + } + + LettuceConnectionFactory factory = new LettuceConnectionFactory(configuration); + factory.afterPropertiesSet(); + + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + + // 使用String序列化方式 + StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); + template.setKeySerializer(stringRedisSerializer); + template.setValueSerializer(stringRedisSerializer); + template.setHashKeySerializer(stringRedisSerializer); + template.setHashValueSerializer(stringRedisSerializer); + + return template; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/config/WxMaConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/config/WxMaConfig.java new file mode 100644 index 0000000..fda7fe5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/config/WxMaConfig.java @@ -0,0 +1,16 @@ +package net.lab1024.sa.admin.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Data +@Component +public class WxMaConfig { + + @Value("${wechat.miniapp.appid}") + private String appid; + + @Value("${wechat.miniapp.secret}") + private String secret; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminCacheConst.java b/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminCacheConst.java new file mode 100644 index 0000000..de077e9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminCacheConst.java @@ -0,0 +1,68 @@ +package net.lab1024.sa.admin.constant; + +import net.lab1024.sa.base.constant.CacheKeyConst; + +/** + * 缓存 key + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2022-01-07 18:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public class AdminCacheConst extends CacheKeyConst { + + public static class Department { + + /** + * 部门列表 + */ + public static final String DEPARTMENT_LIST_CACHE = "department_list_cache"; + + /** + * 部门树 + */ + public static final String DEPARTMENT_TREE_CACHE = "department_tree_cache"; + + /** + * 某个部门以及下级的id列表 + */ + public static final String DEPARTMENT_SELF_CHILDREN_CACHE = "department_self_children_cache"; + + /** + * 部门路径 缓存 + */ + public static final String DEPARTMENT_PATH_CACHE = "department_path_cache"; + + } + + /** + * 分类相关缓存 + */ + public static class Category { + + public static final String CATEGORY_ENTITY = "category_cache"; + + public static final String CATEGORY_SUB = "category_sub_cache"; + + public static final String CATEGORY_TREE = "category_tree_cache"; + } + + /** + * 登录相关 + */ + public static class Login { + + /** + * 请求用户信息 + */ + public static final String REQUEST_EMPLOYEE = "login_request_employee"; + + /** + * 请求用户信息权限 + */ + public static final String USER_PERMISSION = "login_user_permission"; + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminRedisKeyConst.java b/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminRedisKeyConst.java new file mode 100644 index 0000000..07cc8f6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminRedisKeyConst.java @@ -0,0 +1,17 @@ +package net.lab1024.sa.admin.constant; + +import net.lab1024.sa.base.constant.RedisKeyConst; + +/** + * redis key 常量类 + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2022-01-07 18:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public class AdminRedisKeyConst extends RedisKeyConst { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java b/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java new file mode 100644 index 0000000..fb7a630 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java @@ -0,0 +1,59 @@ +package net.lab1024.sa.admin.constant; + +import net.lab1024.sa.base.constant.SwaggerTagConst; + +/** + * swagger + * + * @Author 1024创新实验室:罗伊 + * @Date 2022-01-07 18:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public class AdminSwaggerTagConst extends SwaggerTagConst { + + public static class Business { + public static final String MANAGER_CATEGORY = "ERP进销存-分类管理"; + + public static final String MANAGER_GOODS = "ERP进销存-商品管理"; + + public static final String OA_BANK = "OA办公-银行卡信息"; + + public static final String OA_ENTERPRISE = "OA办公-企业"; + + public static final String OA_INVOICE = "OA办公-发票信息"; + + public static final String OA_NOTICE = "OA办公-通知公告"; + + } + + + public static class System { + + public static final String SYSTEM_LOGIN = "系统-员工登录"; + + public static final String SYSTEM_EMPLOYEE = "系统-员工管理"; + + public static final String SYSTEM_DEPARTMENT = "系统-部门管理"; + + public static final String SYSTEM_MENU = "系统-菜单"; + + public static final String SYSTEM_DATA_SCOPE = "系统-系统-数据范围"; + + public static final String SYSTEM_ROLE = "系统-角色"; + + public static final String SYSTEM_ROLE_DATA_SCOPE = "系统-角色-数据范围"; + + public static final String SYSTEM_ROLE_EMPLOYEE = "系统-角色-员工"; + + public static final String SYSTEM_ROLE_MENU = "系统-角色-菜单"; + + public static final String SYSTEM_POSITION = "系统-职务管理"; + + public static final String SYSTEM_MESSAGE = "系统-消息"; + + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/DySms.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/DySms.java new file mode 100644 index 0000000..0fccddb --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/DySms.java @@ -0,0 +1,77 @@ +package net.lab1024.sa.admin.extend.aliyun; + +import com.aliyun.dysmsapi20170525.Client; +import com.aliyun.dysmsapi20170525.models.SendSmsRequest; +import com.aliyun.dysmsapi20170525.models.SendSmsResponse; +import com.aliyun.tea.TeaException; +import com.aliyun.teaopenapi.models.Config; +import com.aliyun.teautil.models.RuntimeOptions; +import net.lab1024.sa.admin.config.DySmsConfig; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Slf4j +@Component +public class DySms { + @Resource + private DySmsConfig dySmsConfig; + + private static final String endpoint = "dysmsapi.aliyuncs.com"; + private static final String signName = "肝胆相照"; + + /** + * 创建短信客户端 + */ + private Client createClient() throws Exception { + Config config = new Config() + .setAccessKeyId(dySmsConfig.getAccessKey()) + .setAccessKeySecret(dySmsConfig.getAccessSecret()) + .setEndpoint(endpoint); + return new Client(config); + } + + /** + * 发送短信 + * + * @param phoneNumber 手机号 + * @param templateCode 模板CODE + * @param sceneDesc 场景说明,用于日志或调试 + * @param templateParam 模板参数 + */ + public void sendSms(String phoneNumber, String templateCode, String sceneDesc, Map templateParam) { + try { + Client client = createClient(); + ObjectMapper objectMapper = new ObjectMapper(); + String paramJson = objectMapper.writeValueAsString(templateParam); + + SendSmsRequest request = new SendSmsRequest() + .setPhoneNumbers(phoneNumber) + .setSignName(signName) + .setTemplateCode(templateCode) + .setTemplateParam(paramJson); + + // 只用标准的RuntimeOptions,不加任何自定义字段 + RuntimeOptions runtime = new RuntimeOptions(); + + SendSmsResponse response = client.sendSmsWithOptions(request, runtime); + + if (response.getBody() == null || !"OK".equals(response.getBody().getCode())) { + log.error("短信发送失败,手机号:{},场景:{},返回信息:{}", phoneNumber, sceneDesc, response.getBody() != null ? response.getBody().getMessage() : "无返回体"); + throw new RuntimeException("短信发送失败: " + (response.getBody() != null ? response.getBody().getMessage() : "无返回体")); + } else { + log.info("短信发送成功,手机号:{},场景:{},返回信息:{}", phoneNumber, sceneDesc, response.getBody().getMessage()); + } + + } catch (TeaException e) { + log.error("阿里云短信发送异常,手机号:{},场景:{},错误信息:{}", phoneNumber, sceneDesc, e.getMessage(), e); + throw new RuntimeException("阿里云短信发送异常", e); + } catch (Exception e) { + log.error("短信发送异常,手机号:{},场景:{},错误信息:{}", phoneNumber, sceneDesc, e.getMessage(), e); + throw new RuntimeException("短信发送异常", e); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/DySmsConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/DySmsConfig.java new file mode 100644 index 0000000..844cfbf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/DySmsConfig.java @@ -0,0 +1 @@ +// 此文件已移动到 config 目录,请使用 net.lab1024.sa.admin.config.DySmsConfig \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/Oss.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/Oss.java new file mode 100644 index 0000000..33f87ec --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/Oss.java @@ -0,0 +1,116 @@ +package net.lab1024.sa.admin.extend.aliyun; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.model.OSSObject; +import com.aliyun.oss.model.ObjectMetadata; +import com.aliyun.oss.model.PutObjectRequest; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.config.OssConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +@Slf4j +@Component +public class Oss { + private static OssConfig ossConfig; + + private static final Logger logger = LoggerFactory.getLogger(Oss.class); + + public Oss(OssConfig ossConfig) { + Oss.ossConfig = ossConfig; + } + + public static OSS createClient() { + return new OSSClientBuilder().build(ossConfig.getEndpoint(), ossConfig.getAccessKey(), ossConfig.getAccessKeySecret()); + } + + public static boolean putObject(String fileName, byte[] content) { + if (content == null || content.length == 0) { + logger.warn("Failed to upload object to OSS: content is null or empty, fileName={}", fileName); + return false; + } + + if (fileName == null || fileName.trim().isEmpty()) { + logger.warn("Failed to upload object to OSS: fileName is null or empty"); + return false; + } + + OSS client = createClient(); + ByteArrayInputStream inputStream = new ByteArrayInputStream(content); + + try { + // 推断 Content-Type + String contentType = determineContentType(fileName); + + // 创建对象元数据 + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentLength(content.length); + metadata.setContentType(contentType); + + // 执行上传 + PutObjectRequest request = new PutObjectRequest(ossConfig.getBucket(), fileName, inputStream, metadata); + client.putObject(request); + + logger.info("Successfully uploaded object to OSS: bucket={}, fileName={}, size={} bytes", + ossConfig.getBucket(), fileName, content.length); + return true; + + } catch (Exception e) { + logger.error("Failed to upload object to OSS. fileName={}, error={}", fileName, e.getMessage(), e); + return false; + } finally { + try { + inputStream.close(); // 可以不关(ByteArrayInputStream 空操作),但建议写上 + } catch (IOException ignored) { } + client.shutdown(); + } + } + + private static String determineContentType(String fileName) { + if (fileName == null) return "application/octet-stream"; + + int lastDotIndex = fileName.lastIndexOf('.'); + if (lastDotIndex < 0) { + return "application/octet-stream"; + } + + String ext = fileName.substring(lastDotIndex + 1).toLowerCase(); + + return switch (ext) { + case "jpg", "jpeg" -> "image/jpeg"; + case "png" -> "image/png"; + case "gif" -> "image/gif"; + case "bmp" -> "image/bmp"; + case "webp" -> "image/webp"; + case "pdf" -> "application/pdf"; + case "txt" -> "text/plain"; + case "html", "htm" -> "text/html"; + case "xml" -> "application/xml"; + case "json" -> "application/json"; + case "mp4" -> "video/mp4"; + case "avi" -> "video/x-msvideo"; + case "mp3" -> "audio/mpeg"; + default -> "application/octet-stream"; + }; + } + + // 下载文件为 byte[] + public static byte[] getObjectToByte(String fileName) { + OSS client = createClient(); + try (OSSObject ossObject = client.getObject(ossConfig.getBucket(), fileName); + InputStream content = ossObject.getObjectContent()) { + return content.readAllBytes(); + } catch (Exception e) { + log.error("OSS 下载失败: fileName={}, error={}", fileName, e.getMessage(), e); + return null; + } finally { + client.shutdown(); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/OssConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/OssConfig.java new file mode 100644 index 0000000..43946d8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/aliyun/OssConfig.java @@ -0,0 +1 @@ +// 此文件已移动到 config 目录,请使用 net.lab1024.sa.admin.config.OssConfig \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/AppConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/AppConfig.java new file mode 100644 index 0000000..8c30def --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/AppConfig.java @@ -0,0 +1 @@ +// 此文件已移动到 config 目录,请使用 net.lab1024.sa.admin.config.AppConfig \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Base.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Base.java new file mode 100644 index 0000000..d876794 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Base.java @@ -0,0 +1,164 @@ +package net.lab1024.sa.admin.extend.app; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import net.lab1024.sa.base.common.exception.BusinessException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +@Slf4j +public class Base { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 生成签名 + * @param params 需要签名的参数(支持嵌套 Map) + * @param secretKey 密钥 + * @return 签名字符串 + */ + public static String genSignature(Map params, String secretKey) { + try { + // Step 1: 对 Map 进行递归排序 + Map sortedMap = sortMapRecursively(params); + + // Step 2: 转为 JSON 字符串 + String json = objectMapper.writeValueAsString(sortedMap); + + // Step 3: 使用 HMAC-SHA256 签名 + return hmacSha256(json, secretKey); + } catch (JsonProcessingException e) { + return null; + } + } + + /** + * 对 Map 进行递归排序(key 排序),支持嵌套 Map 和 List + */ + public static Map sortMapRecursively(Map data) { + Map sortedMap = new TreeMap<>(); // TreeMap 会自动按 key 排序 + + for (Map.Entry entry : data.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + + if (value instanceof Map) { + // 如果是嵌套 map,递归排序 + @SuppressWarnings("unchecked") + Map nestedMap = (Map) value; + sortedMap.put(key, sortMapRecursively(nestedMap)); + } else if (value instanceof List) { + // 如果是列表,检查每一项是否是 map,如果是则排序 + @SuppressWarnings("unchecked") + List list = (List) value; + List sortedList = new ArrayList<>(); + for (Object item : list) { + if (item instanceof Map) { + @SuppressWarnings("unchecked") + Map nestedItemMap = (Map) item; + sortedList.add(sortMapRecursively(nestedItemMap)); + } else { + sortedList.add(item); + } + } + sortedMap.put(key, sortedList); + } else { + // 普通字段,直接插入 + sortedMap.put(key, value); + } + } + + return sortedMap; + } + + /** + * HMAC-SHA256 加密 + */ + private static String hmacSha256(String data, String key) { + try { + Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); + sha256_HMAC.init(secretKeySpec); + byte[] result = sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8)); + + // 转为 16 进制字符串 + StringBuilder hexString = new StringBuilder(); + for (byte b : result) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) hexString.append('0'); + hexString.append(hex); + } + return hexString.toString(); + } catch (Exception e) { + return null; + } + } + + /** + * 发送 POST JSON 请求 + * @param url 请求地址 + * @param jsonData JSON 字符串 + * @param headers 请求头 + * @return 响应字符串 + */ + public String postJson(String url, String jsonData, Map headers) { + HttpRequest request = HttpRequest.post(url) + .body(jsonData) + .header("Content-Type", "application/json"); + + if (headers != null) { + headers.forEach(request::header); + } + + try (HttpResponse response = request.execute()) { + return response.body(); + } + } + + /** + * 校验签名(使用已反序列化的 dto 对象) + * @param request HttpServletRequest(用于获取 appId 和 sign) + * @param secretKey 签名用的密钥 + * @param dto 请求对象(如 addClinicalVideoApp) + * @param mapper ObjectMapper 实例(用于序列化 dto) + */ + public void checkSign(HttpServletRequest request, String secretKey, Object dto, ObjectMapper mapper) { + try { + String appId = request.getHeader("appId"); + String sign = request.getHeader("sign"); + + if (appId == null || appId.isEmpty()) { + throw new BusinessException("请求未授权(缺少 appId)"); + } + if (sign == null || sign.isEmpty()) { + throw new BusinessException("缺少签名"); + } + + // 转换 dto 为 Map 用于签名生成 + @SuppressWarnings("unchecked") + Map params = mapper.convertValue(dto, Map.class); + + // 生成签名 + String serverSign = genSignature(params, secretKey); + System.out.println("客户端签名: " + sign); + System.out.println("服务端签名: " + serverSign); + + if (!sign.equals(serverSign)) { + throw new BusinessException("签名错误"); + } + } catch (BusinessException e) { + throw e; + } catch (Exception e) { + throw new BusinessException("签名校验失败:" + e.getMessage()); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Hospital/GetHospitalByUuidResponse.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Hospital/GetHospitalByUuidResponse.java new file mode 100644 index 0000000..e691e3e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Hospital/GetHospitalByUuidResponse.java @@ -0,0 +1,48 @@ +package net.lab1024.sa.admin.extend.app.Hospital; + +import lombok.Data; + +@Data +public class GetHospitalByUuidResponse +{ + /** 接口调用状态。200:正常;其它值:调用出错 */ + private int code; + + /** 结果说明。如果接口调用出错,那么返回错误描述。成功则返回 ok */ + private String msg; + + /** 接口返回的用户信息数据 */ + private GetHospitalByUuidData data; + + /** 接口是否调用成功 */ + private boolean success; + + /** 错误信息或提示信息 */ + private String message; + + + /** + * - 详细数据 + */ + @Data + public static class GetHospitalByUuidData { + + /** 医院唯一标识 */ + private String uuid; + + /** 科室 */ + private String name; + + /** 等级 */ + private String level; + + /** 省份 */ + private String prov_name; + + /** 城市 */ + private String city_name; + + /** 医生数量 */ + private Integer expert_num; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Hospital/Hospital.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Hospital/Hospital.java new file mode 100644 index 0000000..67da9d7 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Hospital/Hospital.java @@ -0,0 +1,68 @@ +package net.lab1024.sa.admin.extend.app.Hospital; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONUtil; +import net.lab1024.sa.admin.config.AppConfig; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.admin.extend.app.Base; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Slf4j +@Component +public class Hospital extends Base { + @Resource + private AppConfig appConfig; + + // 根据医院唯一标识获取医院数据 + public GetHospitalByUuidResponse getHospitalByUuid(String hospitalIden) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("hospital_uuid", hospitalIden); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/getHospitalByUuid"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + GetHospitalByUuidResponse result = JSONUtil.toBean(response.body(), GetHospitalByUuidResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + if (result.getData() == null){ + throw new BusinessException("失败"); + } + + return result; + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Reward/Reward.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Reward/Reward.java new file mode 100644 index 0000000..953b49b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Reward/Reward.java @@ -0,0 +1,66 @@ +package net.lab1024.sa.admin.extend.app.Reward; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONUtil; +import net.lab1024.sa.admin.config.AppConfig; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.admin.extend.app.Base; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Slf4j +@Component +public class Reward extends Base { + @Resource + private AppConfig appConfig; + + // 打赏积分 + public RewardResponse RewardPoint(String userUuid,Integer point,String authorUuid) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("user_uuid", userUuid); + requestData.put("bonusPoints", point); + requestData.put("recipients", authorUuid); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/admireBonusPoints"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + RewardResponse result = JSONUtil.toBean(response.body(), RewardResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + return result; + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Reward/RewardResponse.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Reward/RewardResponse.java new file mode 100644 index 0000000..e0bd7f7 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Reward/RewardResponse.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.extend.app.Reward; + +import lombok.Data; + +@Data +public class RewardResponse +{ + /** 接口调用状态。200:正常;其它值:调用出错 */ + private int code; + + /** 结果说明。如果接口调用出错,那么返回错误描述。成功则返回 ok */ + private String msg; + + /** 接口是否调用成功 */ + private boolean success; + + /** 错误信息或提示信息 */ + private String message; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Score/ReportUserScoreResponse.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Score/ReportUserScoreResponse.java new file mode 100644 index 0000000..19ea802 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Score/ReportUserScoreResponse.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.extend.app.Score; + +import lombok.Data; + +@Data +public class ReportUserScoreResponse +{ + /** 接口调用状态。200:正常;其它值:调用出错 */ + private int code; + + /** 结果说明。如果接口调用出错,那么返回错误描述。成功则返回 ok */ + private String msg; + + /** 接口是否调用成功 */ + private boolean success; + + /** 错误信息或提示信息 */ + private String message; + + /** 接口返回的数据 */ + private Integer data; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Score/Score.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Score/Score.java new file mode 100644 index 0000000..4b03733 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Score/Score.java @@ -0,0 +1,66 @@ +package net.lab1024.sa.admin.extend.app.Score; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONUtil; +import net.lab1024.sa.admin.config.AppConfig; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.admin.extend.app.Base; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Slf4j +@Component +public class Score extends Base { + @Resource + private AppConfig appConfig; + + // 上报用户积分 + public ReportUserScoreResponse ReportUserScore(String uuid,Integer bonuspoints,String bonuspointsNote) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("bonuspoints_note", bonuspointsNote); + requestData.put("bonuspoints", bonuspoints); + requestData.put("user_uuid", uuid); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/addBonusPoints"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + ReportUserScoreResponse result = JSONUtil.toBean(response.body(), ReportUserScoreResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + return result; + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserInfo/GetUserInfoResponse.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserInfo/GetUserInfoResponse.java new file mode 100644 index 0000000..c3b8aea --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserInfo/GetUserInfoResponse.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.admin.extend.app.UserInfo; + +import lombok.Data; + +@Data +public class GetUserInfoResponse { + /** 接口调用状态。200:正常;其它值:调用出错 */ + private int code; + + /** 结果说明。如果接口调用出错,那么返回错误描述。成功则返回 ok */ + private String msg; + + /** 接口返回的用户信息数据 */ + private ResponsData data; + + /** 接口是否调用成功 */ + private boolean success; + + /** 错误信息或提示信息 */ + private String message; + + + @Data + public static class ResponsData { + + /** app唯一标识 */ + private String uuid; + + /** 科室 */ + private String officeName; + + /** 姓名 */ + private String realname; + + /** 医院唯一标识 */ + private String hospitalUuid; + + /** 手机号 */ + private String mobile; + + /** 头像地址 */ + private String img_host; + + /** 头像地址 */ + private String photo; + + /** 创建时间 */ + private String createDate; + + /** 职称 */ + private String positionName; + + /** 省份 */ + private String provName; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserInfo/UserInfo.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserInfo/UserInfo.java new file mode 100644 index 0000000..824d69a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserInfo/UserInfo.java @@ -0,0 +1,206 @@ +package net.lab1024.sa.admin.extend.app.UserInfo; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONUtil; +import net.lab1024.sa.admin.extend.app.Base; +import net.lab1024.sa.admin.config.AppConfig; +import net.lab1024.sa.base.common.exception.BusinessException; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Slf4j +@Component +public class UserInfo extends Base { + @Resource + private AppConfig appConfig; + + // 根据手机号获取信息V3 + public GetUserInfoResponse getUserInfoByMobile(String mobile) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("mobile", mobile); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/getInfoByMobileV3"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + GetUserInfoResponse result = JSONUtil.toBean(response.body(), GetUserInfoResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + if (result.getData() == null){ + throw new BusinessException("失败"); + } + + return result; + } + } + + // 根据token获取信息V3 + public GetUserInfoResponse getUserInfoByToken(String appToken) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("token", appToken); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/getInfoByToken"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + GetUserInfoResponse result = JSONUtil.toBean(response.body(), GetUserInfoResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + if (result.getData() == null){ + throw new BusinessException("失败"); + } + + return result; + } + } + + // 根据唯一标识获取信息V3 + public GetUserInfoResponse getUserInfoByUuid(String uuid) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("user_uuid", uuid); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/getInfoByUuid"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + GetUserInfoResponse result = JSONUtil.toBean(response.body(), GetUserInfoResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + if (result.getData() == null){ + throw new BusinessException("失败"); + } + + return result; + } + } + + // 根据姓名获取信息 + public GetUserInfoResponse getUserInfoByName(String doctorName) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("user_name", doctorName); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/getInfoByName"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + GetUserInfoResponse result = JSONUtil.toBean(response.body(), GetUserInfoResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + if (result.getData() == null){ + throw new BusinessException("失败"); + } + + return result; + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserPoint/UserPoint.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserPoint/UserPoint.java new file mode 100644 index 0000000..7d508d0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserPoint/UserPoint.java @@ -0,0 +1,64 @@ +package net.lab1024.sa.admin.extend.app.UserPoint; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONUtil; +import net.lab1024.sa.admin.config.AppConfig; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.admin.extend.app.Base; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Slf4j +@Component +public class UserPoint extends Base { + @Resource + private AppConfig appConfig; + + // 获取用户积分 + public UserPointResponse GetUserPoint(String uuid) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("user_uuid", uuid); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/getBonusPoints"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + UserPointResponse result = JSONUtil.toBean(response.body(), UserPointResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + return result; + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserPoint/UserPointResponse.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserPoint/UserPointResponse.java new file mode 100644 index 0000000..ca47d0d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/UserPoint/UserPointResponse.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.extend.app.UserPoint; + +import lombok.Data; + +@Data +public class UserPointResponse +{ + /** 接口调用状态。200:正常;其它值:调用出错 */ + private int code; + + /** 结果说明。如果接口调用出错,那么返回错误描述。成功则返回 ok */ + private String msg; + + /** 接口是否调用成功 */ + private boolean success; + + /** 错误信息或提示信息 */ + private String message; + + /** 接口返回的数据 */ + private Integer data; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Video/Video.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Video/Video.java new file mode 100644 index 0000000..c66bf02 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/Video/Video.java @@ -0,0 +1,11 @@ +package net.lab1024.sa.admin.extend.app.Video; + +import net.lab1024.sa.admin.extend.app.Base; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class Video extends Base { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/label/GetLabelsResponse.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/label/GetLabelsResponse.java new file mode 100644 index 0000000..4e47c19 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/label/GetLabelsResponse.java @@ -0,0 +1,55 @@ +package net.lab1024.sa.admin.extend.app.label; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class GetLabelsResponse +{ + /** 接口调用状态。200:正常;其它值:调用出错 */ + private int code; + + /** 结果说明。如果接口调用出错,那么返回错误描述。成功则返回 ok */ + private String msg; + + /** 接口返回的用户信息数据 */ + private List data; + + /** 接口是否调用成功 */ + private boolean success; + + /** 错误信息或提示信息 */ + private String message; + + + /** + * 根据统一标签列表 - 详细数据 + */ + @Data + public static class GetLabelsData { + + /** + * 标签名称 + */ + private String name; + + /** + * id + */ + private String id; + + /** + * 子标签数量 + */ + @JsonProperty("children_size") + private Integer childrenSize; + + /** + * p_id + */ + @JsonProperty("p_id") + private String pId; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/label/Label.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/label/Label.java new file mode 100644 index 0000000..a14db37 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/app/label/Label.java @@ -0,0 +1,68 @@ +package net.lab1024.sa.admin.extend.app.label; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import cn.hutool.json.JSONUtil; +import net.lab1024.sa.admin.config.AppConfig; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.admin.extend.app.Base; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Slf4j +@Component +public class Label extends Base { + @Resource + private AppConfig appConfig; + + // 根据医院唯一标识获取医院数据 + public GetLabelsResponse getLabels(String p_id) throws BusinessException { + String timestamp = String.valueOf(System.currentTimeMillis() / 1000); + + // 处理参数 + Map requestData = new HashMap<>(); + requestData.put("p_id", p_id); + requestData.put("platform", appConfig.getPlatform()); + requestData.put("timestamp", timestamp); + + // 生成签名 + String sign = genSignature(requestData,appConfig.getSecretKey()); + + String url = appConfig.getApiUrl() + "/expert-api/getLabels"; + String jsonBody = JSONUtil.toJsonStr(requestData); + log.info("获取app数据参数:{}",jsonBody); + + try(HttpResponse response = HttpRequest.post(url) + .header("Content-Type", "application/json") + .header("sign", sign) + .body(jsonBody) + .execute()){ + + if (response.getStatus() != 200) { + throw new BusinessException("失败"); + } + + // 反序列化 JSON + GetLabelsResponse result = JSONUtil.toBean(response.body(), GetLabelsResponse.class); + log.info("获取app数据返回:{}",result); + if (result.getCode() != 200){ + if (!Objects.equals(result.getMsg(), "")){ + throw new BusinessException(result.getMsg()); + }else{ + throw new BusinessException("失败"); + } + } + + if (result.getData() == null){ + throw new BusinessException("失败"); + } + + return result; + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/EnvConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/EnvConfig.java new file mode 100644 index 0000000..ce56de8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/EnvConfig.java @@ -0,0 +1 @@ +// 此文件已移动到 config 目录,请使用 net.lab1024.sa.admin.config.EnvConfig \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaConfig.java new file mode 100644 index 0000000..65d62b4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaConfig.java @@ -0,0 +1 @@ +// 此文件已移动到 config 目录,请使用 net.lab1024.sa.admin.config.WxMaConfig \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaRedisConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaRedisConfig.java new file mode 100644 index 0000000..a9c1afe --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaRedisConfig.java @@ -0,0 +1,64 @@ +package net.lab1024.sa.admin.extend.weChat; + + +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.concurrent.TimeUnit; + +@Slf4j +public class WxMaRedisConfig extends WxMaDefaultConfigImpl { + + private final RedisTemplate redisTemplate; + private final RedisTemplate prodRedisTemplate; + + public WxMaRedisConfig(RedisTemplate redisTemplate, RedisTemplate prodRedisTemplate) { + this.redisTemplate = redisTemplate; + this.prodRedisTemplate = prodRedisTemplate; + } + + @Override + public String getAccessToken() { + String redisKey = "wx:ma:access_token:" + this.getAppid(); + String token = (String) redisTemplate.opsForValue().get(redisKey); + if (token != null) { + return token; + } + + // 2. 再尝试从 prodRedis 获取 + token = (String) prodRedisTemplate.opsForValue().get(redisKey); + if (token != null) { + return token; + } + + synchronized (this) { + token = (String) redisTemplate.opsForValue().get(redisKey); + if (token != null) return token; + + token = (String) prodRedisTemplate.opsForValue().get(redisKey); + if (token != null) return token; + + try { + String newToken = super.getAccessToken(); // 强制刷新 + long expireSeconds = this.getExpiresTime() - 200L; + + redisTemplate.opsForValue().set(redisKey, newToken, expireSeconds, TimeUnit.SECONDS); + prodRedisTemplate.opsForValue().set(redisKey, newToken, expireSeconds, TimeUnit.SECONDS); + return newToken; + } catch (Exception e) { + log.error("获取access_token失败", e); + throw new RuntimeException("获取access_token失败", e); + } + } + } + + @Override + public void updateAccessToken(String accessToken, int expiresInSeconds) { + String redisKey = "wx:ma:access_token:" + this.getAppid(); + long expireSeconds = Math.max(expiresInSeconds - 200L, 1L); + + redisTemplate.opsForValue().set(redisKey, accessToken, expireSeconds, TimeUnit.SECONDS); + prodRedisTemplate.opsForValue().set(redisKey, accessToken, expireSeconds, TimeUnit.SECONDS); + } +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaServiceConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaServiceConfig.java new file mode 100644 index 0000000..1c8ac4b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaServiceConfig.java @@ -0,0 +1,43 @@ +package net.lab1024.sa.admin.extend.weChat; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import net.lab1024.sa.admin.config.WxMaConfig; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.RedisTemplate; + +@Configuration +public class WxMaServiceConfig { + private final RedisTemplate devRedis; + private final RedisTemplate prodRedis; + + @Resource + private WxMaConfig wxMaConfig; + + public WxMaServiceConfig( + @Qualifier("redisTemplate") RedisTemplate devRedis, + @Qualifier("prodRedisTemplate") RedisTemplate prodRedis + ) { + this.devRedis = devRedis; + this.prodRedis = prodRedis; + } + + @Bean + public WxMaService wxMaService() { + WxMaRedisConfig redisConfig = new WxMaRedisConfig(devRedis, prodRedis); + redisConfig.setAppid(wxMaConfig.getAppid()); + redisConfig.setSecret(wxMaConfig.getSecret()); + + WxMaServiceImpl service = new WxMaServiceImpl(); + service.setWxMaConfig(redisConfig); + return service; + } + + + + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaServiceUtils.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaServiceUtils.java new file mode 100644 index 0000000..b7aaabe --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/weChat/WxMaServiceUtils.java @@ -0,0 +1,88 @@ +package net.lab1024.sa.admin.extend.weChat; + + +import cn.binarywang.wx.miniapp.api.WxMaQrcodeService; +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.WxMaCodeLineColor; +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo; +import net.lab1024.sa.admin.config.EnvConfig; +import jakarta.annotation.Resource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +@Slf4j +@Component +@RequiredArgsConstructor +public class WxMaServiceUtils { + private final WxMaService wxMaService; + + @Resource + private EnvConfig envConfig; + + /** + * 通过 code 换取 session 信息(openid/unionid) + */ + public WxMaJscode2SessionResult getSessionInfo(String code) { + try { + return wxMaService.getUserService().getSessionInfo(code); + } catch (WxErrorException e) { + log.error("获取 session 失败", e); + throw new RuntimeException("微信 session 获取失败", e); + } + } + + /** + * 解密手机号信息 + */ + public WxMaPhoneNumberInfo getPhoneNumber(String code) { + try { + return wxMaService.getUserService().getPhoneNumber(code); // 注意:此方法为新版本推荐方法 + } catch (WxErrorException e) { + log.error("获取手机号失败", e); + throw new RuntimeException("微信手机号获取失败", e); + } + } + + /** + * 获取当前 access_token(仅调试或日志用) + */ + public String getAccessToken() { + try { + return wxMaService.getAccessToken(); + } catch (WxErrorException e) { + log.error("获取 access_token 失败", e); + throw new RuntimeException("获取 access_token 失败", e); + } + } + + /** + * 获取永久小程序码(base64 或保存成文件都可以) + * @param scene 场景值(最长32个可见字符,只能是数字、英文、下划线、减号) + * @param page 跳转页面路径(如 pages/index/index) + * @return 二进制图片数据(image/jpeg) + */ + public byte[] getUnlimitedQrcode(String scene, String page) { + boolean checkPath = false; // 不校验 page 是否存在 + String envVersion = "release"; // 可选:trial、develop、release + if (Objects.equals(envConfig.getActive(), "dev")){ + envVersion = "trial"; + } + + int width = 430; + boolean autoColor = true; + WxMaCodeLineColor lineColor = new WxMaCodeLineColor(); + boolean isHyaline = true; + + try { + WxMaQrcodeService qrcodeService = wxMaService.getQrcodeService(); + return qrcodeService.createWxaCodeUnlimitBytes(scene,page,checkPath,envVersion,width,autoColor,lineColor,isHyaline); + } catch (Exception e) { + throw new RuntimeException("获取小程序码失败", e); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java b/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java new file mode 100644 index 0000000..5bf8c73 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/interceptor/AdminInterceptor.java @@ -0,0 +1,143 @@ +package net.lab1024.sa.admin.interceptor; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.exception.SaTokenException; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.strategy.SaAnnotationStrategy; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee; +import net.lab1024.sa.admin.module.system.login.service.LoginService; +import net.lab1024.sa.base.common.annoation.NoNeedLogin; +import net.lab1024.sa.base.common.code.SystemErrorCode; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.common.util.SmartResponseUtil; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.lang.reflect.Method; + +/** + * admin 拦截器 + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2023/7/26 20:20:33 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室,Since 2012 + */ + +@Component +@Slf4j +public class AdminInterceptor implements HandlerInterceptor { + + @Resource + private LoginService loginService; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + + // OPTIONS请求直接return + if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) { + response.setStatus(HttpStatus.NO_CONTENT.value()); + return false; + } + + boolean isHandler = handler instanceof HandlerMethod; + if (!isHandler) { + return true; + } + + try { + // --------------- 第一步: 根据token 获取用户 --------------- + + String tokenValue = StpUtil.getTokenValue(); + String loginId = (String) StpUtil.getLoginIdByToken(tokenValue); + RequestEmployee requestEmployee = loginService.getLoginEmployee(loginId, request); + + // --------------- 第二步: 校验 登录 --------------- + + Method method = ((HandlerMethod) handler).getMethod(); + NoNeedLogin noNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class); + if (noNeedLogin != null) { + checkActiveTimeout(requestEmployee); + return true; + } + + if (requestEmployee == null) { + SmartResponseUtil.write(response, ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID)); + return false; + } + + // 检测token 活跃频率 + checkActiveTimeout(requestEmployee); + + + // --------------- 第三步: 校验 权限 --------------- + + SmartRequestUtil.setRequestUser(requestEmployee); + if (SaAnnotationStrategy.instance.isAnnotationPresent.apply(method, SaIgnore.class)) { + return true; + } + + // 如果是超级管理员的话,不需要校验权限 + if (requestEmployee.getAdministratorFlag()) { + return true; + } + + SaAnnotationStrategy.instance.checkMethodAnnotation.accept(method); + + } catch (SaTokenException e) { + /* + * sa-token 异常状态码 + * 具体请看: https://sa-token.cc/doc.html#/fun/exception-code + */ + int code = e.getCode(); + if (code == 11041 || code == 11051) { + SmartResponseUtil.write(response, ResponseDTO.error(UserErrorCode.NO_PERMISSION)); + } else if (code == 11016) { + SmartResponseUtil.write(response, ResponseDTO.error(UserErrorCode.LOGIN_ACTIVE_TIMEOUT)); + } else if (code >= 11011 && code <= 11015) { + SmartResponseUtil.write(response, ResponseDTO.error(UserErrorCode.LOGIN_STATE_INVALID)); + } else { + SmartResponseUtil.write(response, ResponseDTO.error(UserErrorCode.PARAM_ERROR)); + } + return false; + } catch (Throwable e) { + SmartResponseUtil.write(response, ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR)); + log.error(e.getMessage(), e); + return false; + } + + // 通过验证 + return true; + } + + + /** + * 检测:token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结 + */ + private void checkActiveTimeout(RequestEmployee requestEmployee) { + // 用户不在线,也不用检测 + if (requestEmployee == null) { + return; + } + + StpUtil.checkActiveTimeout(); + StpUtil.updateLastActiveToNow(); + } + + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + // 清除上下文 + SmartRequestUtil.remove(); + } +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/controller/AreaController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/controller/AreaController.java new file mode 100644 index 0000000..ecf3811 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/controller/AreaController.java @@ -0,0 +1,53 @@ +package net.lab1024.sa.admin.module.business.area.controller; + +import net.lab1024.sa.admin.module.business.area.domain.form.AreaQueryForm; +import net.lab1024.sa.admin.module.business.area.domain.vo.AreaVO; +import net.lab1024.sa.admin.module.business.area.service.AreaService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.*; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * 省市区 Controller + * + * @Author xing + * @Date 2025-08-04 15:00:58 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "省市区") +public class AreaController { + + @Resource + private AreaService areaService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/area/queryPage") + @SaCheckPermission("area:query") + public ResponseDTO> queryPage(@RequestBody @Valid AreaQueryForm queryForm) { + return ResponseDTO.ok(areaService.queryPage(queryForm)); + } + + + @Operation(summary = "获取省份 @author xing") + @GetMapping("/area/provList") + @SaCheckPermission("area:query") + public ResponseDTO> provList() { + return ResponseDTO.ok(areaService.provList()); + } + + @Operation(summary = "获取市区 @author xing") + @GetMapping("/area/cityList/{parent}") + @SaCheckPermission("area:query") + public ResponseDTO> cityList(@PathVariable Long parent) { + return ResponseDTO.ok(areaService.cityList(parent)); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/dao/AreaDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/dao/AreaDao.java new file mode 100644 index 0000000..40d68b8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/dao/AreaDao.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.business.area.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.area.domain.entity.AreaEntity; +import net.lab1024.sa.admin.module.business.area.domain.form.AreaQueryForm; +import net.lab1024.sa.admin.module.business.area.domain.vo.AreaVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; +import org.springframework.stereotype.Component; + +/** + * 省市区 Dao + * + * @Author xing + * @Date 2025-08-04 15:00:58 + * @Copyright gdxz + */ + +@Mapper +public interface AreaDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") AreaQueryForm queryForm); + + /** + * 获取省份列表 + * @return + */ + @Select("select * from t_area where parent is null") + List provList(); + + /** + * 获取城市列表 + * @return + */ + @Select("select * from t_area where parent = #{parent}") + List cityList(long parent); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/entity/AreaEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/entity/AreaEntity.java new file mode 100644 index 0000000..bc383a2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/entity/AreaEntity.java @@ -0,0 +1,62 @@ +package net.lab1024.sa.admin.module.business.area.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 省市区 实体类 + * + * @Author xing + * @Date 2025-08-04 15:00:58 + * @Copyright gdxz + */ + +@Data +@TableName("area") +public class AreaEntity { + + /** + * 主键 + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 创建时间 + */ + private LocalDateTime createDate; + + /** + * 更新时间 + */ + private LocalDateTime modifyDate; + + /** + * 排序 + */ + private Integer orders; + + /** + * 全名 + */ + private String fullName; + + /** + * 名称 + */ + private String name; + + /** + * 树路径 + */ + private String treePath; + + /** + * 父节点 + */ + private Long parent; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/form/AreaQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/form/AreaQueryForm.java new file mode 100644 index 0000000..119dc54 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/form/AreaQueryForm.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.area.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 省市区 分页查询表单 + * + * @Author xing + * @Date 2025-08-04 15:00:58 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class AreaQueryForm extends PageParam { + + @Schema(description = "名称") + private String keywords; + + @Schema(description = "上级城市") + private Long parent; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/vo/AreaVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/vo/AreaVO.java new file mode 100644 index 0000000..3cb4c85 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/domain/vo/AreaVO.java @@ -0,0 +1,43 @@ +package net.lab1024.sa.admin.module.business.area.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 省市区 列表VO + * + * @Author xing + * @Date 2025-08-04 15:00:58 + * @Copyright gdxz + */ + +@Data +public class AreaVO { + + + @Schema(description = "主键") + private Long id; + + @Schema(description = "创建时间") + private LocalDateTime createDate; + + @Schema(description = "更新时间") + private LocalDateTime modifyDate; + + @Schema(description = "排序") + private Integer orders; + + @Schema(description = "全名") + private String fullName; + + @Schema(description = "名称") + private String name; + + @Schema(description = "树路径") + private String treePath; + + @Schema(description = "父节点") + private Long parent; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/manager/AreaManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/manager/AreaManager.java new file mode 100644 index 0000000..b697e3e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/manager/AreaManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.area.manager; + +import net.lab1024.sa.admin.module.business.area.domain.entity.AreaEntity; +import net.lab1024.sa.admin.module.business.area.dao.AreaDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 省市区 Manager + * + * @Author xing + * @Date 2025-08-04 15:00:58 + * @Copyright gdxz + */ +@Service +public class AreaManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/service/AreaService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/service/AreaService.java new file mode 100644 index 0000000..450e8d8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/area/service/AreaService.java @@ -0,0 +1,49 @@ +package net.lab1024.sa.admin.module.business.area.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.area.dao.AreaDao; +import net.lab1024.sa.admin.module.business.area.domain.entity.AreaEntity; +import net.lab1024.sa.admin.module.business.area.domain.form.AreaQueryForm; +import net.lab1024.sa.admin.module.business.area.domain.vo.AreaVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 省市区 Service + * + * @Author xing + * @Date 2025-08-04 15:00:58 + * @Copyright gdxz + */ + +@Service +public class AreaService { + + @Resource + private AreaDao areaDao; + + /** + * 分页查询 + */ + public PageResult queryPage(AreaQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = areaDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + public List provList() { + return areaDao.provList(); + } + + public List cityList(Long parent) { + return areaDao.cityList(parent); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/controller/BasicHospitalController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/controller/BasicHospitalController.java new file mode 100644 index 0000000..51de051 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/controller/BasicHospitalController.java @@ -0,0 +1,48 @@ +package net.lab1024.sa.admin.module.business.basicHospital.controller; + +import net.lab1024.sa.admin.module.business.basicHospital.domain.form.BasicHospitalQueryForm; +import net.lab1024.sa.admin.module.business.basicHospital.domain.form.BasicHospitalQueryListForm; +import net.lab1024.sa.admin.module.business.basicHospital.domain.vo.BasicHospitalVO; +import net.lab1024.sa.admin.module.business.basicHospital.service.BasicHospitalService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * 基础数据-医院 Controller + * + * @Author xing + * @Date 2025-08-04 14:06:17 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "基础数据-医院") +public class BasicHospitalController { + + @Resource + private BasicHospitalService basicHospitalService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/basicHospital/queryPage") + @SaCheckPermission("basicHospital:query") + public ResponseDTO> queryPage(@RequestBody @Valid BasicHospitalQueryForm queryForm) { + return ResponseDTO.ok(basicHospitalService.queryPage(queryForm)); + } + + @Operation(summary = "列表查询 @author xing") + @PostMapping("/basicHospital/queryList") + @SaCheckPermission("basicHospital:list") + public ResponseDTO> queryList(@RequestBody @Valid BasicHospitalQueryListForm queryForm) { + return ResponseDTO.ok(basicHospitalService.queryList(queryForm)); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/dao/BasicHospitalDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/dao/BasicHospitalDao.java new file mode 100644 index 0000000..2928d38 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/dao/BasicHospitalDao.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.admin.module.business.basicHospital.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; +import net.lab1024.sa.admin.module.business.basicHospital.domain.form.BasicHospitalQueryForm; +import net.lab1024.sa.admin.module.business.basicHospital.domain.form.BasicHospitalQueryListForm; +import net.lab1024.sa.admin.module.business.basicHospital.domain.vo.BasicHospitalVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 基础数据-医院 Dao + * + * @Author xing + * @Date 2025-08-04 14:06:17 + * @Copyright gdxz + */ + +@Mapper +public interface BasicHospitalDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") BasicHospitalQueryForm queryForm); + + /** + * 列表 查询 + * + * @param queryForm + * @return + */ + List queryList(@Param("queryForm") BasicHospitalQueryListForm queryForm); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/entity/BasicHospitalEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/entity/BasicHospitalEntity.java new file mode 100644 index 0000000..9c5ae1c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/entity/BasicHospitalEntity.java @@ -0,0 +1,81 @@ +package net.lab1024.sa.admin.module.business.basicHospital.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 基础数据-医院 实体类 + * + * @Author xing + * @Date 2025-08-04 14:06:17 + * @Copyright gdxz + */ + +@Data +@TableName("basic_hospital") +public class BasicHospitalEntity { + + /** + * 主键id + */ + @TableId + private Long hospitalId; + + /** + * app唯一标识 + */ + private String hospitalIden; + + /** + * 医院名称 + */ + private String hospitalName; + + /** + * 来源(2:肝胆相照 3:佳动例) + */ + private Integer source; + + /** + * 医院等级 + */ + private String hospitalLevel; + + /** + * 医生数量 + */ + private Integer doctorNumber; + + /** + * 省份 + */ + private String province; + + /** + * 城市 + */ + private String city; + + /** + * 区县 + */ + private String county; + + /** + * 地址 + */ + private String address; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/form/BasicHospitalQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/form/BasicHospitalQueryForm.java new file mode 100644 index 0000000..618eb32 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/form/BasicHospitalQueryForm.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.admin.module.business.basicHospital.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; + +/** + * 基础数据-医院 分页查询表单 + * + * @Author xing + * @Date 2025-08-04 14:06:17 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class BasicHospitalQueryForm extends PageParam { + + @Schema(description = "医院名称") + private String keywords; + + @Schema(description = "医院等级") + private String hospitalLevel; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/form/BasicHospitalQueryListForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/form/BasicHospitalQueryListForm.java new file mode 100644 index 0000000..f648c6d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/form/BasicHospitalQueryListForm.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.admin.module.business.basicHospital.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import net.lab1024.sa.base.common.domain.PageParam; + +/** + * 基础数据-医院 列表查询表单 + * + * @Author xing + * @Date 2025-08-04 14:06:17 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class BasicHospitalQueryListForm { + + @Schema(description = "医院名称") + private String keywords; + + @Schema(description = "医院等级") + private String hospitalLevel; + + @Schema(description = "数量") + private Integer limit = 10; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/vo/BasicHospitalVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/vo/BasicHospitalVO.java new file mode 100644 index 0000000..f53e5d1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/domain/vo/BasicHospitalVO.java @@ -0,0 +1,55 @@ +package net.lab1024.sa.admin.module.business.basicHospital.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 基础数据-医院 列表VO + * + * @Author xing + * @Date 2025-08-04 14:06:17 + * @Copyright gdxz + */ + +@Data +public class BasicHospitalVO { + + + @Schema(description = "主键id") + private Long hospitalId; + + @Schema(description = "app唯一标识") + private String hospitalIden; + + @Schema(description = "医院名称") + private String hospitalName; + + @Schema(description = "来源(2:肝胆相照 3:佳动例)") + private Integer source; + + @Schema(description = "医院等级") + private String hospitalLevel; + + @Schema(description = "医生数量") + private Integer doctorNumber; + + @Schema(description = "省份") + private String province; + + @Schema(description = "城市") + private String city; + + @Schema(description = "区县") + private String county; + + @Schema(description = "地址") + private String address; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/manager/BasicHospitalManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/manager/BasicHospitalManager.java new file mode 100644 index 0000000..206a055 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/manager/BasicHospitalManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.basicHospital.manager; + +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; +import net.lab1024.sa.admin.module.business.basicHospital.dao.BasicHospitalDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 基础数据-医院 Manager + * + * @Author xing + * @Date 2025-08-04 14:06:17 + * @Copyright gdxz + */ +@Service +public class BasicHospitalManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/service/BasicHospitalService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/service/BasicHospitalService.java new file mode 100644 index 0000000..7c34424 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicHospital/service/BasicHospitalService.java @@ -0,0 +1,48 @@ +package net.lab1024.sa.admin.module.business.basicHospital.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.basicHospital.dao.BasicHospitalDao; +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; +import net.lab1024.sa.admin.module.business.basicHospital.domain.form.BasicHospitalQueryForm; +import net.lab1024.sa.admin.module.business.basicHospital.domain.form.BasicHospitalQueryListForm; +import net.lab1024.sa.admin.module.business.basicHospital.domain.vo.BasicHospitalVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 基础数据-医院 Service + * + * @Author xing + * @Date 2025-08-04 14:06:17 + * @Copyright gdxz + */ + +@Service +public class BasicHospitalService { + + @Resource + private BasicHospitalDao basicHospitalDao; + + /** + * 分页查询 + */ + public PageResult queryPage(BasicHospitalQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = basicHospitalDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 列表查询 + */ + public List queryList(BasicHospitalQueryListForm queryForm) { + return basicHospitalDao.queryList(queryForm); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/controller/BasicSensitiveWordController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/controller/BasicSensitiveWordController.java new file mode 100644 index 0000000..16349ea --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/controller/BasicSensitiveWordController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.basicSensitiveWord.controller; + +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.form.BasicSensitiveWordQueryForm; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.vo.BasicSensitiveWordVO; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.service.BasicSensitiveWordService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 基础数据-敏感词 Controller + * + * @Author xing + * @Date 2025-08-11 00:32:07 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "基础数据-敏感词") +public class BasicSensitiveWordController { + + @Resource + private BasicSensitiveWordService basicSensitiveWordService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/basicSensitiveWord/queryPage") + @SaCheckPermission("basicSensitiveWord:query") + public ResponseDTO> queryPage(@RequestBody @Valid BasicSensitiveWordQueryForm queryForm) { + return ResponseDTO.ok(basicSensitiveWordService.queryPage(queryForm)); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/dao/BasicSensitiveWordDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/dao/BasicSensitiveWordDao.java new file mode 100644 index 0000000..6688326 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/dao/BasicSensitiveWordDao.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.basicSensitiveWord.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.entity.BasicSensitiveWordEntity; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.form.BasicSensitiveWordQueryForm; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.vo.BasicSensitiveWordVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 基础数据-敏感词 Dao + * + * @Author xing + * @Date 2025-08-11 00:32:07 + * @Copyright gdxz + */ + +@Mapper +public interface BasicSensitiveWordDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") BasicSensitiveWordQueryForm queryForm); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/entity/BasicSensitiveWordEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/entity/BasicSensitiveWordEntity.java new file mode 100644 index 0000000..5afe704 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/entity/BasicSensitiveWordEntity.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 基础数据-敏感词 实体类 + * + * @Author xing + * @Date 2025-08-11 00:32:07 + * @Copyright gdxz + */ + +@Data +@TableName("basic_sensitive_word") +public class BasicSensitiveWordEntity { + + /** + * 主键id + */ + @TableId + private Long id; + + /** + * 敏感词 + */ + private String word; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/form/BasicSensitiveWordQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/form/BasicSensitiveWordQueryForm.java new file mode 100644 index 0000000..60c4335 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/form/BasicSensitiveWordQueryForm.java @@ -0,0 +1,19 @@ +package net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 基础数据-敏感词 分页查询表单 + * + * @Author xing + * @Date 2025-08-11 00:32:07 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class BasicSensitiveWordQueryForm extends PageParam { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/vo/BasicSensitiveWordVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/vo/BasicSensitiveWordVO.java new file mode 100644 index 0000000..c5cadec --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/domain/vo/BasicSensitiveWordVO.java @@ -0,0 +1,31 @@ +package net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 基础数据-敏感词 列表VO + * + * @Author xing + * @Date 2025-08-11 00:32:07 + * @Copyright gdxz + */ + +@Data +public class BasicSensitiveWordVO { + + + @Schema(description = "主键id") + private Long id; + + @Schema(description = "敏感词") + private String word; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/manager/BasicSensitiveWordManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/manager/BasicSensitiveWordManager.java new file mode 100644 index 0000000..fcd5b64 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/manager/BasicSensitiveWordManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.basicSensitiveWord.manager; + +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.entity.BasicSensitiveWordEntity; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.dao.BasicSensitiveWordDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 基础数据-敏感词 Manager + * + * @Author xing + * @Date 2025-08-11 00:32:07 + * @Copyright gdxz + */ +@Service +public class BasicSensitiveWordManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/service/BasicSensitiveWordService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/service/BasicSensitiveWordService.java new file mode 100644 index 0000000..0fc3700 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/basicSensitiveWord/service/BasicSensitiveWordService.java @@ -0,0 +1,159 @@ +package net.lab1024.sa.admin.module.business.basicSensitiveWord.service; + +import java.time.Duration; +import java.util.*; +import java.util.stream.Collectors; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.dao.BasicSensitiveWordDao; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.entity.BasicSensitiveWordEntity; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.form.BasicSensitiveWordQueryForm; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.domain.vo.BasicSensitiveWordVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 基础数据-敏感词 Service + * + * @Author xing + * @Date 2025-08-11 00:32:07 + * @Copyright gdxz + */ + +@Service +public class BasicSensitiveWordService { + + @Resource + private BasicSensitiveWordDao basicSensitiveWordDao; + + @Resource + private RedisTemplate redisTemplate; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 分页查询 + */ + public PageResult queryPage(BasicSensitiveWordQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = basicSensitiveWordDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + private static final String REDIS_SENSITIVE_WORD_KEY = "sensitive:word:list"; + private static final long REDIS_EXPIRE_MINUTES = 30; + + + + // 主过滤方法 + public FilterResult filter(String comment) { + List wordList = loadSensitiveWords(); + if (wordList == null || wordList.isEmpty()) { + return new FilterResult(comment, 0); + } + + TrieNode root = buildTrie(wordList); + return doFilter(comment, root); + } + + // 加载敏感词(可替换为数据库查询) + private List loadSensitiveWords() { + List wordList = new ArrayList<>(); + + // 尝试从 Redis 获取 + String wordJson = redisTemplate.opsForValue().get(REDIS_SENSITIVE_WORD_KEY); + if (wordJson != null && !wordJson.isEmpty()) { + try { + // 反序列化 JSON 字符串为 List + wordList = objectMapper.readValue(wordJson, new TypeReference>() {}); + } catch (Exception e) { + return wordList; + } + }else{ + // Redis 无数据,则查询 DB + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + List basicSensitiveWords = basicSensitiveWordDao.selectList(queryWrapper); // 你自己的 DAO 方法 + if (basicSensitiveWords != null && !basicSensitiveWords.isEmpty()) { + wordList = basicSensitiveWords.stream() + .map(BasicSensitiveWordEntity::getWord) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + try { + String wordListJson = objectMapper.writeValueAsString(wordList); + redisTemplate.opsForValue().set(REDIS_SENSITIVE_WORD_KEY, wordListJson, Duration.ofMinutes(REDIS_EXPIRE_MINUTES)); + } catch (Exception e) { + return wordList; + } + } + } + + return wordList; + } + + // 构建字典树 + private TrieNode buildTrie(List words) { + TrieNode root = new TrieNode(); + for (String word : words) { + TrieNode node = root; + for (char ch : word.toCharArray()) { + node.children.putIfAbsent(ch, new TrieNode()); + node = node.children.get(ch); + } + node.isEnd = true; + } + return root; + } + + // 实际过滤逻辑 + private FilterResult doFilter(String comment, TrieNode root) { + char[] chars = comment.toCharArray(); + int isSensitive = 0; + + for (int i = 0; i < chars.length; i++) { + TrieNode node = root; + int j = i; + while (j < chars.length && node.children.containsKey(chars[j])) { + node = node.children.get(chars[j]); + if (node.isEnd) { + for (int k = i; k <= j; k++) { + chars[k] = '*'; + } + isSensitive = 1; + break; + } + j++; + } + } + + return new FilterResult(new String(chars), isSensitive); + } + + // Trie 节点内部类 + private static class TrieNode { + boolean isEnd = false; + Map children = new HashMap<>(); + } + + // 返回结果封装 + public static class FilterResult { + public final String comment; + public final int hasSensitive; + + public FilterResult(String comment, int hasSensitive) { + this.comment = comment; + this.hasSensitive = hasSensitive; + } + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinical/service/CaseClinicalService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinical/service/CaseClinicalService.java new file mode 100644 index 0000000..051ec83 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinical/service/CaseClinicalService.java @@ -0,0 +1,245 @@ +package net.lab1024.sa.admin.module.business.caseClinical.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.dao.CaseClinicalVideoDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDao; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.dao.CaseClinicalArticleDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDoctorDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalHospitalDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalLabelDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalHospitalEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalLabelEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; + +@Service +public class CaseClinicalService { + @Resource + private CaseClinicalArticleDao caseClinicalArticleDao; + + @Resource + private CaseClinicalVideoDao caseClinicalVideoDao; + + @Resource + private StatsCaseClinicalDoctorDao statsCaseClinicalDoctorDao; + + @Resource + private StatsCaseClinicalHospitalDao statsCaseClinicalHospitalDao; + + @Resource + private StatsCaseClinicalLabelDao statsCaseClinicalLabelDao; + + /** + * 新增标签统计 + * @param labelIden + * @param labelName + * @param type 类型 1:文章 2:视频 + * @param lastPushDate + * @return + */ + @Transactional + public StatsCaseClinicalLabelEntity IncStatsCaseClinicalLabel(String labelIden, String labelName, Integer type, LocalDateTime lastPushDate){ + LambdaQueryWrapper mapQueryWrapper = new LambdaQueryWrapper<>(); + mapQueryWrapper.eq(StatsCaseClinicalLabelEntity::getLabelIden, labelIden); + StatsCaseClinicalLabelEntity statsCaseClinicalLabel = statsCaseClinicalLabelDao.selectOne(mapQueryWrapper); + if (statsCaseClinicalLabel == null) { + statsCaseClinicalLabel = new StatsCaseClinicalLabelEntity(); + statsCaseClinicalLabel.setLabelIden(labelIden); + statsCaseClinicalLabel.setLabelName(labelName); + if (type == 1){ + statsCaseClinicalLabel.setArticleNum(1); + }else if(type == 2){ + statsCaseClinicalLabel.setVideoNum(1); + } + if (lastPushDate!=null){ + statsCaseClinicalLabel.setLastPushDate(lastPushDate); + } + statsCaseClinicalLabelDao.insert(statsCaseClinicalLabel); + }else{ + if (type == 1){ + statsCaseClinicalLabelDao.inc(statsCaseClinicalLabel.getLabelIden(),"article_num",1); + }else{ + statsCaseClinicalLabelDao.inc(statsCaseClinicalLabel.getLabelIden(),"video_num",1); + } + } + + return statsCaseClinicalLabel; + } + + /** + * 减少标签统计 + * @param labelIden + * @param type 类型 1:文章 2:视频 + * @return + */ + @Transactional + public StatsCaseClinicalLabelEntity DecStatsCaseClinicalLabel(String labelIden,Integer type){ + LambdaQueryWrapper mapQueryWrapper = new LambdaQueryWrapper<>(); + mapQueryWrapper.eq(StatsCaseClinicalLabelEntity::getLabelIden, labelIden); + StatsCaseClinicalLabelEntity statsCaseClinicalLabel = statsCaseClinicalLabelDao.selectOne(mapQueryWrapper); + if (statsCaseClinicalLabel == null) { + return null; + }else{ + if (type == 1){ + // 最后一篇文章发表时间 + LocalDateTime lastPushDate = caseClinicalArticleDao.selectLastArticlePushDateByLabelId(labelIden); + if (lastPushDate != null){ + statsCaseClinicalLabel.setLastPushDate(lastPushDate); + statsCaseClinicalLabelDao.updateById(statsCaseClinicalLabel); + } + + statsCaseClinicalLabelDao.dec(statsCaseClinicalLabel.getLabelIden(),"article_num",1); + }else{ + // 最后一篇文章发表时间 + LocalDateTime lastPushDate = caseClinicalVideoDao.selectLastVideoPushDateByLabelId(labelIden); + if (lastPushDate != null){ + statsCaseClinicalLabel.setLastPushDate(lastPushDate); + statsCaseClinicalLabelDao.updateById(statsCaseClinicalLabel); + } + statsCaseClinicalLabelDao.dec(statsCaseClinicalLabel.getLabelIden(),"video_num",1); + } + } + + return statsCaseClinicalLabel; + } + + // 新增医生统计 + @Transactional + public StatsCaseClinicalDoctorEntity IncStatsCaseClinicalDoctor(String doctorId, Integer type, LocalDateTime lastPushDate){ + LambdaQueryWrapper mapQueryWrapper = new LambdaQueryWrapper<>(); + mapQueryWrapper.eq(StatsCaseClinicalDoctorEntity::getDoctorId, doctorId); + StatsCaseClinicalDoctorEntity statsCaseClinicalDoctor = statsCaseClinicalDoctorDao.selectOne(mapQueryWrapper); + if (statsCaseClinicalDoctor == null) { + statsCaseClinicalDoctor = new StatsCaseClinicalDoctorEntity(); + statsCaseClinicalDoctor.setDoctorId(Long.valueOf(doctorId)); + + if (type == 1){ + statsCaseClinicalDoctor.setArticleNum(1); + }else if(type == 2){ + statsCaseClinicalDoctor.setVideoNum(1); + } + if (lastPushDate!=null){ + statsCaseClinicalDoctor.setLastPushDate(lastPushDate); + } + statsCaseClinicalDoctorDao.insert(statsCaseClinicalDoctor); + }else{ + if (type == 1){ + statsCaseClinicalDoctorDao.inc(statsCaseClinicalDoctor.getDoctorId(),"article_num",1); + }else{ + statsCaseClinicalDoctorDao.inc(statsCaseClinicalDoctor.getDoctorId(),"video_num",1); + } + } + + return statsCaseClinicalDoctor; + } + + /** + * 减少医生统计 + * @param doctorId + * @param type 类型 1:文章 2:视频 + * @return + */ + @Transactional + public StatsCaseClinicalDoctorEntity DecStatsCaseClinicalDoctor(String doctorId,Integer type){ + LambdaQueryWrapper mapQueryWrapper = new LambdaQueryWrapper<>(); + mapQueryWrapper.eq(StatsCaseClinicalDoctorEntity::getDoctorId, doctorId); + StatsCaseClinicalDoctorEntity statsCaseClinicalDoctor = statsCaseClinicalDoctorDao.selectOne(mapQueryWrapper); + if (statsCaseClinicalDoctor == null) { + return null; + }else{ + if (type == 1){ + // 最后一篇文章发表时间 + LocalDateTime lastPushDate = caseClinicalArticleDao.selectLastArticlePushDateByDoctorId(Long.valueOf(doctorId)); + if (lastPushDate != null){ + statsCaseClinicalDoctor.setLastPushDate(lastPushDate); + statsCaseClinicalDoctorDao.updateById(statsCaseClinicalDoctor); + } + + statsCaseClinicalDoctorDao.dec(statsCaseClinicalDoctor.getDoctorId(),"article_num",1); + }else{ + // 最后一篇文章发表时间 + LocalDateTime lastPushDate = caseClinicalVideoDao.selectLastVideoPushDateByDoctorId(Long.valueOf(doctorId)); + if (lastPushDate != null){ + statsCaseClinicalDoctor.setLastPushDate(lastPushDate); + statsCaseClinicalDoctorDao.updateById(statsCaseClinicalDoctor); + } + statsCaseClinicalDoctorDao.dec(statsCaseClinicalDoctor.getDoctorId(),"video_num",1); + } + } + + return statsCaseClinicalDoctor; + } + + // 新增医院统计 + @Transactional + public StatsCaseClinicalHospitalEntity IncStatsCaseClinicalHospital(String hospitalId, Integer type, LocalDateTime lastPushDate){ + LambdaQueryWrapper mapQueryWrapper = new LambdaQueryWrapper<>(); + mapQueryWrapper.eq(StatsCaseClinicalHospitalEntity::getHospitalId, hospitalId); + StatsCaseClinicalHospitalEntity statsCaseClinicalHospital = statsCaseClinicalHospitalDao.selectOne(mapQueryWrapper); + if (statsCaseClinicalHospital == null) { + statsCaseClinicalHospital = new StatsCaseClinicalHospitalEntity(); + statsCaseClinicalHospital.setHospitalId(Long.valueOf(hospitalId)); + + if (type == 1){ + statsCaseClinicalHospital.setArticleNum(1); + }else if(type == 2){ + statsCaseClinicalHospital.setVideoNum(1); + } + + if (lastPushDate!=null){ + statsCaseClinicalHospital.setLastPushDate(lastPushDate); + } + statsCaseClinicalHospitalDao.insert(statsCaseClinicalHospital); + }else{ + if (type == 1){ + statsCaseClinicalHospitalDao.inc(statsCaseClinicalHospital.getHospitalId(),"article_num",1); + }else{ + statsCaseClinicalHospitalDao.inc(statsCaseClinicalHospital.getHospitalId(),"video_num",1); + } + } + + return statsCaseClinicalHospital; + } + + /** + * 减少医院统计 + * @param hospitalId + * @param type 类型 1:文章 2:视频 + * @return + */ + @Transactional + public StatsCaseClinicalHospitalEntity DecStatsCaseClinicalHospital(String hospitalId,Integer type){ + LambdaQueryWrapper mapQueryWrapper = new LambdaQueryWrapper<>(); + mapQueryWrapper.eq(StatsCaseClinicalHospitalEntity::getHospitalId, hospitalId); + StatsCaseClinicalHospitalEntity statsCaseClinicalHospital = statsCaseClinicalHospitalDao.selectOne(mapQueryWrapper); + if (statsCaseClinicalHospital == null) { + return null; + }else{ + if (type == 1){ + // 最后一篇文章发表时间 + LocalDateTime lastPushDate = caseClinicalArticleDao.selectLastArticlePushDateByHospitalId(Long.valueOf(hospitalId)); + if (lastPushDate != null){ + statsCaseClinicalHospital.setLastPushDate(lastPushDate); + statsCaseClinicalHospitalDao.updateById(statsCaseClinicalHospital); + } + + statsCaseClinicalHospitalDao.dec(statsCaseClinicalHospital.getHospitalId(),"article_num",1); + }else{ + // 最后一篇文章发表时间 + LocalDateTime lastPushDate = caseClinicalVideoDao.selectLastVideoPushDateByHospitalId(Long.valueOf(hospitalId)); + if (lastPushDate != null){ + statsCaseClinicalHospital.setLastPushDate(lastPushDate); + statsCaseClinicalHospitalDao.updateById(statsCaseClinicalHospital); + } + statsCaseClinicalHospitalDao.dec(statsCaseClinicalHospital.getHospitalId(),"video_num",1); + } + } + + return statsCaseClinicalHospital; + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/controller/CaseClinicalArticleController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/controller/CaseClinicalArticleController.java new file mode 100644 index 0000000..61c6cc4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/controller/CaseClinicalArticleController.java @@ -0,0 +1,113 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.controller; + +import com.amazonaws.Response; +import net.lab1024.sa.admin.extend.app.label.GetLabelsResponse; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.CaseClinicalArticleAddForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.CaseClinicalArticleLabelQueryListForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.CaseClinicalArticleQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.CaseClinicalArticleUpdateForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.CaseClinicalArticleStatusUpdateForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.AppCaseClinicalArticleLabelVO; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleVO; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.service.CaseClinicalArticleLabelService; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.service.CaseClinicalArticleService; +import net.lab1024.sa.base.common.domain.ValidateList; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.RequestParam; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import java.util.ArrayList; +import java.util.List; + +/** + * 病例库-临床-文章 Controller + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "病例库-临床-文章") +public class CaseClinicalArticleController { + + @Resource + private CaseClinicalArticleService caseClinicalArticleService; + + @Resource + private CaseClinicalArticleLabelService caseClinicalArticleLabelService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/caseClinicalArticle/queryPage") + @SaCheckPermission("caseClinicalArticle:query") + public ResponseDTO> queryPage(@RequestBody @Valid CaseClinicalArticleQueryForm queryForm) { + return ResponseDTO.ok(caseClinicalArticleService.queryPage(queryForm)); + } + + @Operation(summary = "添加 @author xing") + @PostMapping("/caseClinicalArticle/add") + @SaCheckPermission("caseClinicalArticle:add") + public ResponseDTO add(@RequestBody @Valid CaseClinicalArticleAddForm addForm) { + return caseClinicalArticleService.add(addForm); + } + + @Operation(summary = "更新 @author xing") + @PostMapping("/caseClinicalArticle/update") + @SaCheckPermission("caseClinicalArticle:update") + public ResponseDTO update(@RequestBody @Valid CaseClinicalArticleUpdateForm updateForm) { + return caseClinicalArticleService.update(updateForm); + } + + @Operation(summary = "批量删除 @author xing") + @PostMapping("/caseClinicalArticle/batchDelete") + @SaCheckPermission("caseClinicalArticle:delete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return caseClinicalArticleService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author xing") + @GetMapping("/caseClinicalArticle/delete/{articleId}") + @SaCheckPermission("caseClinicalArticle:delete") + public ResponseDTO batchDelete(@PathVariable Long articleId) { + return caseClinicalArticleService.delete(articleId); + } + + @Operation(summary = "生成文章分享二维码 @author xing") + @PostMapping("/caseClinicalArticle/addUnlimitedQrcode/{articleId}") + @SaCheckPermission("caseClinicalArticle:addUnlimitedQrcode") + public ResponseDTO addUnlimitedQrcode(@PathVariable Long articleId) { + caseClinicalArticleService.addUnlimitedQrcode(articleId); + return ResponseDTO.ok(); + } + + @Operation(summary = "获取文章详情 @author xing") + @GetMapping("/caseClinicalArticle/getDetail/{articleId}") + @SaCheckPermission("caseClinicalArticle:query") + public ResponseDTO getDetail(@PathVariable Long articleId) { + return caseClinicalArticleService.getDetail(articleId); + } + + /** + * 获取疾病标签列表 + */ + @Operation(summary = "获取疾病标签列表 @author xing") + @GetMapping("/caseClinicalLabel/queryList") + @SaCheckPermission("caseClinicalArticle:query") + public ResponseDTO> getCaseLabel(@RequestParam(defaultValue = "0") String pId) { + return caseClinicalArticleLabelService.getCaseLabel(pId); + } + + @Operation(summary = "修改状态 @author xing") + @PostMapping("/caseClinicalArticle/status/update") + @SaCheckPermission("caseClinicalArticle:update") + public ResponseDTO statusUpdate(@RequestBody @Valid CaseClinicalArticleStatusUpdateForm updateForm) { + return caseClinicalArticleService.updateStatus(updateForm.getArticleId(), updateForm.getStatus()); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/dao/CaseClinicalArticleDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/dao/CaseClinicalArticleDao.java new file mode 100644 index 0000000..09c5739 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/dao/CaseClinicalArticleDao.java @@ -0,0 +1,78 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.dao; + +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.CaseClinicalArticleQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleVO; + +import java.time.LocalDateTime; +import java.util.List; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + * 病例库-临床-文章 Dao + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Mapper +public interface CaseClinicalArticleDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") CaseClinicalArticleQueryForm queryForm); + + /** + * Inc 自增 + * @param articleId 文章 ID + * @param field 字段名称 + * @param numeral 增加的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical SET ${field} = ${field} + #{numeral} WHERE stats_id = #{statsId}") + int inc(@Param("statsId") Long articleId, @Param("field") String field, @Param("numeral") int numeral); + + /** + * Dec 自减 + * + * @param articleId 文章 ID + * @param field 字段名称 + * @param numeral 减少的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical " + + "SET ${field} = CASE WHEN ${field} >= #{numeral} THEN ${field} - #{numeral} ELSE 0 END " + + "WHERE stats_id = #{statsId}") + int dec(@Param("statsId") Long articleId, @Param("field") String field, @Param("numeral") int numeral); + + /** + * 根据医院ID查询该医院最后一篇文章的发表时间 + * @param hospitalId 医院ID + * @return 最新发表时间,无数据时返回 null + */ + LocalDateTime selectLastArticlePushDateByHospitalId(@Param("hospitalId") Long hospitalId); + + /** + * 根据医生ID查询该医生最后一篇文章的发表时间 + * @param doctorId 医院ID + * @return 最新发表时间,无数据时返回 null + */ + LocalDateTime selectLastArticlePushDateByDoctorId(@Param("doctorId") Long doctorId); + + /** + * 根据医院ID查询该医院最后一篇文章的发表时间 + * @param labelIden 标签唯一标识 + * @return 最新发表时间,无数据时返回 null + */ + LocalDateTime selectLastArticlePushDateByLabelId(@Param("labelIden") String labelIden); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/dao/CaseClinicalArticleLabelDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/dao/CaseClinicalArticleLabelDao.java new file mode 100644 index 0000000..4484e3b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/dao/CaseClinicalArticleLabelDao.java @@ -0,0 +1,24 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleLabelEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleLabelVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 病例库-临床-文章-标签 Dao + * + * @Author xing + * @Date 2025-08-06 17:41:09 + * @Copyright gdxz + */ + +@Mapper +public interface CaseClinicalArticleLabelDao extends BaseMapper { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/entity/CaseClinicalArticleEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/entity/CaseClinicalArticleEntity.java new file mode 100644 index 0000000..0007129 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/entity/CaseClinicalArticleEntity.java @@ -0,0 +1,105 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import java.util.List; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.entity.CaseClinicalArticleAuthorEntity; + +/** + * 病例库-临床-文章 实体类 + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Data +@TableName("case_clinical_article") +public class CaseClinicalArticleEntity { + + /** + * 主键id + */ + @TableId + private Long articleId; + + /** + * 标题 + */ + private String articleTitle; + + /** + * 状态(1:正常 2:禁用) + */ + private Integer articleStatus; + + /** + * 删除状态(0:否 1:是) + */ + private Integer deleteStatus; + + /** + * 阅读量 + */ + private Integer readNum; + + /** + * 收藏量 + */ + private Integer collectNum; + + /** + * 评论数 + */ + private Integer commentNum; + + /** + * 证书图片 + */ + private String certImage; + + /** + * 发表时间 + */ + private LocalDateTime pushDate; + + /** + * 是否外部链接(0:否 1:是) + */ + private Integer isLink; + + /** + * 外部链接地址 + */ + private String isLinkUrl; + + /** + * 分享二维码地址 + */ + @TableField("share_qrcode") + private String shareQrcode; + + /** + * 内容 + */ + private String articleContent; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + + // 作者 + @TableField(exist = false) + private List caseClinicalArticleAuthor; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/entity/CaseClinicalArticleLabelEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/entity/CaseClinicalArticleLabelEntity.java new file mode 100644 index 0000000..c3a9d80 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/entity/CaseClinicalArticleLabelEntity.java @@ -0,0 +1,51 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-临床-文章-标签 实体类 + * + * @Author xing + * @Date 2025-08-06 17:41:09 + * @Copyright gdxz + */ + +@Data +@TableName("case_clinical_article_label") +public class CaseClinicalArticleLabelEntity { + + /** + * 主键id + */ + @TableId + private Long articleLabelId; + + /** + * 临床文章id + */ + private Long articleId; + + /** + * app唯一标识 + */ + private String appIden; + + /** + * 标签名称 + */ + private String labelName; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleAddForm.java new file mode 100644 index 0000000..f799fd6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleAddForm.java @@ -0,0 +1,59 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo.CaseClinicalArticleAuthorVO; +import net.lab1024.sa.base.common.json.deserializer.FileKeyVoDeserializer; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.CaseClinicalArticleAuthorForm; + +/** + * 病例库-临床-文章 新建表单 + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalArticleAddForm { + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "标题 不能为空") + private String articleTitle; + + @Schema(description = "状态(1:正常 2:禁用)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态(1:正常 2:禁用) 不能为空") + private Integer articleStatus; + + @Schema(description = "发表时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "发表时间 不能为空") + private LocalDateTime pushDate; + + @Schema(description = "是否外部链接(0:否 1:是)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否外部链接(0:否 1:是) 不能为空") + private Integer isLink; + + @Schema(description = "外部链接地址") + private String isLinkUrl; + + @Schema(description = "分享二维码地址") + @JsonDeserialize(using = FileKeyVoDeserializer.class) + private String shareQrcode; + + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "内容 不能为空") + private String articleContent; + + @Schema(description = "作者列表") + private List authorList; + + @Schema(description = "标签列表") + private List labelList; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleAuthorForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleAuthorForm.java new file mode 100644 index 0000000..5ea9518 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleAuthorForm.java @@ -0,0 +1,31 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 病例库-临床-文章-作者 表单 + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalArticleAuthorForm { + + @Schema(description = "医生ID") + private Long doctorId; + + @Schema(description = "医生姓名") + private String doctorName; + + @Schema(description = "医院名称") + private String hospitalName; + + @Schema(description = "医院省份") + private String hospitalProvince; + + @Schema(description = "医院城市") + private String hospitalCity; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleLabelForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleLabelForm.java new file mode 100644 index 0000000..feb657c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleLabelForm.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 病例库-临床-文章-标签 表单 + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalArticleLabelForm { + + @Schema(description = "医生ID") + private Long doctorId; + + @Schema(description = "唯一标识") + private String appIden; // app唯一标识 + + @Schema(description = "标签名称") + private String labelName; // 标签名称 +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleLabelQueryListForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleLabelQueryListForm.java new file mode 100644 index 0000000..29dde27 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleLabelQueryListForm.java @@ -0,0 +1,25 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import net.lab1024.sa.base.common.domain.PageParam; + +import java.time.LocalDate; + +/** + * 病例库-临床-文章 分页查询表单 + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseClinicalArticleLabelQueryListForm { + + @Schema(description = "父级ID,默认为0表示获取顶级标签") + private String pId = "0"; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleQueryForm.java new file mode 100644 index 0000000..02d9dd7 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleQueryForm.java @@ -0,0 +1,36 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDate; + +/** + * 病例库-临床-文章 分页查询表单 + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseClinicalArticleQueryForm extends PageParam { + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "状态") + private Integer articleStatus; + + @Schema(description = "删除状态") + private Integer deleteStatus; + + @Schema(description = "发表时间") + private LocalDate pushDateBegin; + + @Schema(description = "发表时间") + private LocalDate pushDateEnd; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleStatusUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleStatusUpdateForm.java new file mode 100644 index 0000000..fa23264 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleStatusUpdateForm.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +/** + * 病例库-临床-文章 状态更新表单 + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ +@Data +@Schema(description = "病例库-临床-文章 状态更新表单") +public class CaseClinicalArticleStatusUpdateForm { + + @Schema(description = "文章ID") + @NotNull(message = "文章ID不能为空") + private Long articleId; + + @Schema(description = "状态 1:正常 2:禁用") + @NotNull(message = "状态不能为空") + private Integer status; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleUpdateForm.java new file mode 100644 index 0000000..e40a207 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/form/CaseClinicalArticleUpdateForm.java @@ -0,0 +1,65 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import lombok.Data; +import net.lab1024.sa.base.common.json.deserializer.FileKeyVoDeserializer; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.CaseClinicalArticleAuthorForm; +import java.util.List; + +/** + * 病例库-临床-文章 更新表单 + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalArticleUpdateForm { + + @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "主键id 不能为空") + private Long articleId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "标题 不能为空") + private String articleTitle; + + @Schema(description = "状态(1:正常 2:禁用)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态(1:正常 2:禁用) 不能为空") + private Integer articleStatus; + + @Schema(description = "删除状态(0:否 1:是)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "删除状态(0:否 1:是) 不能为空") + private Integer deleteStatus; + + @Schema(description = "发表时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "发表时间 不能为空") + private LocalDateTime pushDate; + + @Schema(description = "是否外部链接(0:否 1:是)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否外部链接(0:否 1:是) 不能为空") + private Integer isLink; + + @Schema(description = "外部链接地址") + private String isLinkUrl; + + @Schema(description = "分享二维码地址") + @JsonDeserialize(using = FileKeyVoDeserializer.class) + private String shareQrcode; + + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "内容 不能为空") + private String articleContent; + + @Schema(description = "作者列表") + public List authorList; + + @Schema(description = "标签列表") + private List labelList; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/AppCaseClinicalArticleLabelVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/AppCaseClinicalArticleLabelVO.java new file mode 100644 index 0000000..d8ddc1a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/AppCaseClinicalArticleLabelVO.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 病例库-临床-文章-标签 列表VO + * + * @Author xing + * @Date 2025-08-06 17:41:09 + * @Copyright gdxz + */ + +@Data +public class AppCaseClinicalArticleLabelVO { + /** + * app唯一标识 + */ + @Schema(description = "唯一标识") + private String appIden; + + /** + * 标签名称 + */ + @Schema(description = "标签名称") + private String labelName; + + /** + * 是否存在子标签,0:否 1:是 + */ + @Schema(description = "是否存在子标签") + private Integer isSub = 0; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/CaseClinicalArticleLabelVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/CaseClinicalArticleLabelVO.java new file mode 100644 index 0000000..ac03c46 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/CaseClinicalArticleLabelVO.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-临床-文章-标签 列表VO + * + * @Author xing + * @Date 2025-08-06 17:41:09 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalArticleLabelVO { + + + @Schema(description = "主键id") + private Long articleLabelId; + + @Schema(description = "临床文章id") + private Long articleId; + + @Schema(description = "app唯一标识") + private String appIden; + + @Schema(description = "标签名称") + private String labelName; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/CaseClinicalArticleVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/CaseClinicalArticleVO.java new file mode 100644 index 0000000..f0377f8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/domain/vo/CaseClinicalArticleVO.java @@ -0,0 +1,80 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo; + +import cn.hutool.core.bean.BeanUtil; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo.CaseClinicalArticleAuthorVO; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleLabelVO; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; +import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer; + +/** + * 病例库-临床-文章 列表VO + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalArticleVO { + @Schema(description = "主键id") + private Long articleId; + + @Schema(description = "标题") + private String articleTitle; + + @Schema(description = "状态(1:正常 2:禁用)") + private Integer articleStatus; + + @Schema(description = "删除状态(0:否 1:是)") + private Integer deleteStatus; + + @Schema(description = "阅读量") + private Integer readNum; + + @Schema(description = "收藏量") + private Integer collectNum; + + @Schema(description = "评论数") + private Integer commentNum; + + @Schema(description = "证书图片") +// @JsonSerialize(using = FileKeyVoSerializer.class) + private String certImage; + + @Schema(description = "发表时间") + private LocalDateTime pushDate; + + @Schema(description = "是否外部链接(0:否 1:是)") + private Integer isLink; + + @Schema(description = "外部链接地址") + private String isLinkUrl; + + @Schema(description = "分享二维码地址") +// @JsonSerialize(using = FileKeyVoSerializer.class) + private String shareQrcode; + + @Schema(description = "内容") + private String articleContent; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + + @Schema(description = "作者数据") + private List caseClinicalArticleAuthor; + + @Schema(description = "标签数据") + private List caseClinicalArticleLabel; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/manager/CaseClinicalArticleLabelManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/manager/CaseClinicalArticleLabelManager.java new file mode 100644 index 0000000..edd56e6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/manager/CaseClinicalArticleLabelManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.manager; + +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleLabelEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.dao.CaseClinicalArticleLabelDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 病例库-临床-文章-标签 Manager + * + * @Author xing + * @Date 2025-08-06 17:41:09 + * @Copyright gdxz + */ +@Service +public class CaseClinicalArticleLabelManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/manager/CaseClinicalArticleManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/manager/CaseClinicalArticleManager.java new file mode 100644 index 0000000..4f2c189 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/manager/CaseClinicalArticleManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.manager; + +import net.lab1024.sa.admin.module.business.caseClinicalArticle.dao.CaseClinicalArticleDao; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleEntity; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 病例库-临床-文章 Manager + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ +@Service +public class CaseClinicalArticleManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/service/CaseClinicalArticleLabelService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/service/CaseClinicalArticleLabelService.java new file mode 100644 index 0000000..7e4e77d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/service/CaseClinicalArticleLabelService.java @@ -0,0 +1,71 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.service; + +import java.util.ArrayList; +import java.util.List; + +import com.amazonaws.Response; +import net.lab1024.sa.admin.extend.app.label.GetLabelsResponse; +import net.lab1024.sa.admin.extend.app.label.Label; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.dao.CaseClinicalArticleLabelDao; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleLabelEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.AppCaseClinicalArticleLabelVO; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleLabelVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; + +/** + * 病例库-临床-文章-标签 Service + * + * @Author xing + * @Date 2025-08-06 17:41:09 + * @Copyright gdxz + */ + +@Slf4j +@Service +public class CaseClinicalArticleLabelService { + + @Resource + private CaseClinicalArticleLabelDao caseClinicalArticleLabelDao; + + @Resource + private Label label; + + /** + * 获取疾病标签数据 + */ + public ResponseDTO> getCaseLabel(String pid) { + try { + GetLabelsResponse result = label.getLabels(pid); + List datas = result.getData(); + + List labelDtoList = new ArrayList<>(); + for (GetLabelsResponse.GetLabelsData d : datas) { + AppCaseClinicalArticleLabelVO dto = new AppCaseClinicalArticleLabelVO(); + dto.setAppIden(d.getId()); + dto.setLabelName(d.getName()); + if (d.getChildrenSize() > 0){ + dto.setIsSub(1); + } + + labelDtoList.add(dto); + } + + return ResponseDTO.ok(labelDtoList); + } catch (Exception e) { + log.error("获取疾病标签数据失败: {}", e.getMessage(), e); + return ResponseDTO.userErrorParam("获取疾病标签数据失败: " + e.getMessage()); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/service/CaseClinicalArticleService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/service/CaseClinicalArticleService.java new file mode 100644 index 0000000..e2df5e1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticle/service/CaseClinicalArticleService.java @@ -0,0 +1,819 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticle.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import net.lab1024.sa.admin.extend.app.UserInfo.GetUserInfoResponse; +import net.lab1024.sa.admin.module.business.basicHospital.dao.BasicHospitalDao; +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; +import net.lab1024.sa.admin.module.business.caseClinical.service.CaseClinicalService; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.dao.CaseClinicalArticleDao; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.dao.CaseClinicalArticleLabelDao; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleLabelEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.form.*; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleVO; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleLabelVO; +import net.lab1024.sa.admin.extend.weChat.WxMaServiceUtils; +import net.lab1024.sa.admin.extend.aliyun.Oss; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorCertDao; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorCertEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDao; +import net.lab1024.sa.admin.module.business.user.service.UserService; +import net.lab1024.sa.admin.util.ImageUtil; +import net.lab1024.sa.admin.util.Replace; +import net.lab1024.sa.base.common.exception.BusinessException; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import org.springframework.beans.factory.annotation.Value; + +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.dao.CaseClinicalArticleAuthorDao; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.entity.CaseClinicalArticleAuthorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo.CaseClinicalArticleAuthorVO; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorDao; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.base.common.util.SmartResponseUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import net.lab1024.sa.admin.util.Replace; + +import jakarta.annotation.Resource; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; + +/** + * 病例库-临床-文章 Service + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Service +public class CaseClinicalArticleService { + + @Resource + private CaseClinicalArticleDao caseClinicalArticleDao; + + @Resource + private CaseClinicalService caseClinicalService; + + @Resource + private StatsCaseClinicalDao statsCaseClinicalDao; + + @Resource + private CaseClinicalArticleAuthorDao caseClinicalArticleAuthorDao; + + @Resource + private CaseClinicalDoctorDao caseClinicalDoctorDao; + + @Resource + private BasicHospitalDao basicHospitalDao; + + @Resource + private WxMaServiceUtils wxMaServiceUtils; + + @Resource + private CaseClinicalArticleLabelDao caseClinicalArticleLabelDao; + + @Resource + private UserService userService; + + @Resource + private CaseClinicalDoctorCertDao caseClinicalDoctorCertDao; + + @Value("${spring.profiles.active:prod}") + private String activeProfile; + + /** + * 分页查询 + */ + public PageResult queryPage(CaseClinicalArticleQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = caseClinicalArticleDao.queryPage(page, queryForm); + for (CaseClinicalArticleVO vo : list) { + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalArticleAuthorEntity::getArticleId, vo.getArticleId()); + List caseClinicalArticleAuthors = caseClinicalArticleAuthorDao.selectList(authorQueryWrapper); + + List caseClinicalArticleAuthorVOs = SmartBeanUtil.copyList(caseClinicalArticleAuthors, CaseClinicalArticleAuthorVO.class); + + // 为每个作者VO设置医生数据 + for (CaseClinicalArticleAuthorVO authorVO : caseClinicalArticleAuthorVOs) { + // 查询医生 + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectById(authorVO.getDoctorId()); + if (caseClinicalDoctor != null) { + // 查询医生所属医院 + BasicHospitalEntity basicHospital = basicHospitalDao.selectById(caseClinicalDoctor.getHospitalId()); + if (basicHospital != null) { + caseClinicalDoctor.setBasicHospital(basicHospital); + } + + // 转换为VO并设置医院信息 + CaseClinicalDoctorVO caseClinicalDoctorVO = SmartBeanUtil.copy(caseClinicalDoctor, CaseClinicalDoctorVO.class); + if (basicHospital != null) { + caseClinicalDoctorVO.setHospitalName(basicHospital.getHospitalName()); + caseClinicalDoctorVO.setHospitalProvince(basicHospital.getProvince()); + caseClinicalDoctorVO.setHospitalCity(basicHospital.getCity()); + } + + authorVO.setCaseClinicalDoctor(caseClinicalDoctorVO); + } + + } + + vo.setCaseClinicalArticleAuthor(caseClinicalArticleAuthorVOs); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalArticleLabelEntity::getArticleId, vo.getArticleId()); + List caseClinicalArticleLabels = caseClinicalArticleLabelDao.selectList(labelQueryWrapper); + + // 转换为VO + List caseClinicalArticleLabelVOs = SmartBeanUtil.copyList(caseClinicalArticleLabels, CaseClinicalArticleLabelVO.class); + vo.setCaseClinicalArticleLabel(caseClinicalArticleLabelVOs); + } + + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 添加 + */ + @Transactional + public ResponseDTO add(CaseClinicalArticleAddForm addForm) { + // 新增文章 + CaseClinicalArticleEntity caseClinicalArticle = SmartBeanUtil.copy(addForm, CaseClinicalArticleEntity.class); + caseClinicalArticleDao.insert(caseClinicalArticle); + + // 新增统计 + IncClinicalArticleStats(String.valueOf(caseClinicalArticle.getArticleId()),4,1); + + // 生成文章分享二维码 + byte[] qrcodeBytes = addUnlimitedQrcode(caseClinicalArticle.getArticleId()); + if (qrcodeBytes == null || qrcodeBytes.length == 0) { + return ResponseDTO.userErrorParam("添加失败"); + } + + // 处理文章作者 + HandleArticleAuthor(caseClinicalArticle,addForm.getAuthorList(),qrcodeBytes); + + // 处理文章标签 + HandleArticleLabel(caseClinicalArticle,addForm.getLabelList()); + + return ResponseDTO.ok(); + } + + /** + * 更新 + * + */ + @Transactional + public ResponseDTO update(CaseClinicalArticleUpdateForm updateForm) { + // 获取文章数据 + CaseClinicalArticleEntity caseClinicalArticle = caseClinicalArticleDao.selectById(updateForm.getArticleId()); + if (caseClinicalArticle == null) { + throw new BusinessException("修改失败"); + } + + // 修改 + if (!Objects.equals(caseClinicalArticle.getArticleTitle(), updateForm.getArticleTitle())) { + caseClinicalArticle.setArticleTitle(updateForm.getArticleTitle()); + } + + if (!Objects.equals(caseClinicalArticle.getPushDate(), updateForm.getPushDate())) { + caseClinicalArticle.setPushDate(updateForm.getPushDate()); + } + + if (!Objects.equals(caseClinicalArticle.getIsLink(), updateForm.getIsLink())) { + caseClinicalArticle.setIsLink(updateForm.getIsLink()); + } + + if (!Objects.equals(caseClinicalArticle.getIsLinkUrl(), updateForm.getIsLinkUrl())) { + caseClinicalArticle.setIsLinkUrl(updateForm.getIsLinkUrl()); + } + + if (!Objects.equals(caseClinicalArticle.getArticleContent(), updateForm.getArticleContent())) { + caseClinicalArticle.setArticleContent(updateForm.getArticleContent()); + } + + // 如果文章状态发生改变,修正统计数据 + if (!Objects.equals(caseClinicalArticle.getArticleStatus(), updateForm.getArticleStatus())) { + caseClinicalArticle.setArticleStatus(updateForm.getArticleStatus()); + + // 修改统计数量 + DecClinicalArticleStats(String.valueOf(caseClinicalArticle.getArticleId()),4,1); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalArticleLabelEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleLabels = caseClinicalArticleLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalArticleLabelEntity label : caseClinicalArticleLabels){ + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(),1); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalArticleAuthorEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleAuthors = caseClinicalArticleAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalArticleAuthorEntity author : caseClinicalArticleAuthors){ + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId,author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 减少医生统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()),1); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),1); + } + } + + caseClinicalArticleDao.updateById(caseClinicalArticle); + + // 处理文章作者 + HandleArticleAuthor(caseClinicalArticle,updateForm.getAuthorList(),null); + + // 处理文章标签 + HandleArticleLabel(caseClinicalArticle,updateForm.getLabelList()); + + return ResponseDTO.ok(); + } + + /** + * 批量删除 + */ + @Transactional + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)){ + return ResponseDTO.ok(); + } + + for (Long articleId : idList) { + if (null == articleId){ + throw new BusinessException("删除失败"); + } + + CaseClinicalArticleEntity caseClinicalArticle = caseClinicalArticleDao.selectById(articleId); + if (caseClinicalArticle == null){ + throw new BusinessException("删除失败"); + } + + // 修改为删除 + caseClinicalArticle.setDeleteStatus(1); + caseClinicalArticleDao.updateById(caseClinicalArticle); + + // 修改统计数量 + DecClinicalArticleStats(String.valueOf(caseClinicalArticle.getArticleId()),4,1); + + // 获取视频标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalArticleLabelEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleLabels = caseClinicalArticleLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalArticleLabelEntity label : caseClinicalArticleLabels){ + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(),1); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalArticleAuthorEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleAuthors = caseClinicalArticleAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalArticleAuthorEntity author : caseClinicalArticleAuthors){ + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId,author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 减少医生统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()),1); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),1); + } + + caseClinicalArticleDao.deleteById(articleId); + } + + return ResponseDTO.ok(); + } + + /** + * 单个删除 + */ + public ResponseDTO delete(Long articleId) { + if (null == articleId){ + return ResponseDTO.ok(); + } + + CaseClinicalArticleEntity caseClinicalArticle = caseClinicalArticleDao.selectById(articleId); + if (caseClinicalArticle == null){ + return ResponseDTO.userErrorParam("删除失败"); + } + + // 修改为删除 + caseClinicalArticle.setDeleteStatus(1); + caseClinicalArticleDao.updateById(caseClinicalArticle); + + // 修改统计数量 + DecClinicalArticleStats(String.valueOf(caseClinicalArticle.getArticleId()),4,1); + + // 获取视频标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalArticleLabelEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleLabels = caseClinicalArticleLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalArticleLabelEntity label : caseClinicalArticleLabels){ + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(),1); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalArticleAuthorEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleAuthors = caseClinicalArticleAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalArticleAuthorEntity author : caseClinicalArticleAuthors){ + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId,author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 减少医生统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()),1); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),1); + } + + return ResponseDTO.ok(); + } + + /** + * 生成文章分享二维码 + */ + public byte[] addUnlimitedQrcode(Long articleId) { + try { + // 检查文章是否存在 + CaseClinicalArticleEntity article = caseClinicalArticleDao.selectById(articleId); + if (article == null) { + throw new BusinessException("文章不存在"); + } + + // 生成二维码参数 + String scene = "?id=" + articleId + "&type=1"; + String page = "pages/detail/detail"; + + // 生成二维码 + byte[] qrcodeBytes = wxMaServiceUtils.getUnlimitedQrcode(scene, page); + + // 生成文件名 + String fileName; + String no = "a" + articleId; + + // 根据环境设置路径 + String envPath = Objects.equals(activeProfile, "dev") ? "dev/" : "prod/"; + fileName = envPath + "static/images/" + no + ".png"; + + // 上传到OSS + boolean res = Oss.putObject(fileName, qrcodeBytes); + if (!res) { + throw new BusinessException("上传二维码失败"); + } + + // 更新文章记录 + article.setShareQrcode("/" + fileName); + caseClinicalArticleDao.updateById(article); + + return qrcodeBytes; + } catch (Exception e) { + throw new BusinessException(e.getMessage()); + } + } + + /** + * 获取文章详情 + */ + public ResponseDTO getDetail(Long articleId) { + CaseClinicalArticleEntity entity = caseClinicalArticleDao.selectById(articleId); + if (entity == null) { + return ResponseDTO.userErrorParam("文章不存在"); + } + + CaseClinicalArticleVO vo = SmartBeanUtil.copy(entity, CaseClinicalArticleVO.class); + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalArticleAuthorEntity::getArticleId, articleId); + List caseClinicalArticleAuthors = caseClinicalArticleAuthorDao.selectList(authorQueryWrapper); + + List caseClinicalArticleAuthorVOs = SmartBeanUtil.copyList(caseClinicalArticleAuthors, CaseClinicalArticleAuthorVO.class); + + // 为每个作者VO设置医生数据 + for (CaseClinicalArticleAuthorVO authorVO : caseClinicalArticleAuthorVOs) { + // 查询医生 + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectById(authorVO.getDoctorId()); + if (caseClinicalDoctor != null) { + // 查询医生所属医院 + BasicHospitalEntity basicHospital = basicHospitalDao.selectById(caseClinicalDoctor.getHospitalId()); + if (basicHospital != null) { + caseClinicalDoctor.setBasicHospital(basicHospital); + } + + // 转换为VO并设置医院信息 + CaseClinicalDoctorVO caseClinicalDoctorVO = SmartBeanUtil.copy(caseClinicalDoctor, CaseClinicalDoctorVO.class); + if (basicHospital != null) { + caseClinicalDoctorVO.setHospitalName(basicHospital.getHospitalName()); + caseClinicalDoctorVO.setHospitalProvince(basicHospital.getProvince()); + caseClinicalDoctorVO.setHospitalCity(basicHospital.getCity()); + } + + authorVO.setCaseClinicalDoctor(caseClinicalDoctorVO); + } + } + + vo.setCaseClinicalArticleAuthor(caseClinicalArticleAuthorVOs); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalArticleLabelEntity::getArticleId, articleId); + List caseClinicalArticleLabels = caseClinicalArticleLabelDao.selectList(labelQueryWrapper); + + // 转换为VO + List caseClinicalArticleLabelVOs = SmartBeanUtil.copyList(caseClinicalArticleLabels, CaseClinicalArticleLabelVO.class); + vo.setCaseClinicalArticleLabel(caseClinicalArticleLabelVOs); + + vo.setShareQrcode(Replace.addOssDomain(vo.getShareQrcode())); + return ResponseDTO.ok(vo); + } + + /** + * 更新文章状态 + */ + public ResponseDTO updateStatus(Long articleId, Integer status) { + if (null == articleId) { + return ResponseDTO.userErrorParam("文章ID不能为空"); + } + + CaseClinicalArticleEntity caseClinicalArticle = caseClinicalArticleDao.selectById(articleId); + if (caseClinicalArticle == null) { + return ResponseDTO.userErrorParam("文章不存在"); + } + + // 如果状态没有变化,直接返回 + if (Objects.equals(caseClinicalArticle.getArticleStatus(), status)) { + return ResponseDTO.ok(); + } + + // 更新状态 + caseClinicalArticle.setArticleStatus(status); + caseClinicalArticleDao.updateById(caseClinicalArticle); + + // 如果状态发生改变,修正统计数据 + if (status == 2) { + // 状态改为禁用,减少统计数量 + DecClinicalArticleStats(String.valueOf(caseClinicalArticle.getArticleId()), 4, 1); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalArticleLabelEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleLabels = caseClinicalArticleLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalArticleLabelEntity label : caseClinicalArticleLabels) { + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(), 1); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalArticleAuthorEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleAuthors = caseClinicalArticleAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalArticleAuthorEntity author : caseClinicalArticleAuthors) { + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId, author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 减少医生统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()), 1); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()), 1); + } + } else if (status == 1) { + // 状态改为正常,增加统计数量 + IncClinicalArticleStats(String.valueOf(caseClinicalArticle.getArticleId()), 4, 1); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalArticleLabelEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleLabels = caseClinicalArticleLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalArticleLabelEntity label : caseClinicalArticleLabels) { + // 增加标签统计 + LocalDateTime lastPushDate = caseClinicalArticleDao.selectLastArticlePushDateByLabelId(label.getAppIden()); + caseClinicalService.IncStatsCaseClinicalLabel(label.getAppIden(), label.getLabelName(), 1, lastPushDate); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalArticleAuthorEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleAuthors = caseClinicalArticleAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalArticleAuthorEntity author : caseClinicalArticleAuthors) { + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId, author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 增加医生统计 + LocalDateTime lastPushDate = caseClinicalArticleDao.selectLastArticlePushDateByDoctorId(caseClinicalDoctor.getDoctorId()); + caseClinicalService.IncStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()), 1, lastPushDate); + + // 增加医院统计 + caseClinicalService.IncStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()), 1, lastPushDate); + } + } + + return ResponseDTO.ok(); + } + + /** + * 新增文章的统计字段 + * @param articleId 文章id + * @param type 类型:1:阅读量 2:收藏量 3:评论数 4:文章数 + */ + public boolean IncClinicalArticleStats(String articleId,Integer type,Integer num){ + try { + String caseClinicalArticleField = ""; // 具体文章 + String statsCaseClinicalField = ""; // 全部文章 + + // 阅读 + if (type == 1){ + caseClinicalArticleField = "read_num"; // 具体文章 + statsCaseClinicalField = "article_read_num"; // 全部文章 + } + + // 收藏 + if (type == 2){ + caseClinicalArticleField = "collect_num"; // 具体文章 + statsCaseClinicalField = "article_collect_num"; // 全部文章 + } + + // 评论 + if (type == 3){ + caseClinicalArticleField = "comment_num"; // 具体文章 + statsCaseClinicalField = "article_comment_num"; // 全部文章 + } + + // 文章数 + if (type == 4){ + statsCaseClinicalField = "article_num"; // 全部文章 + } + + if (!caseClinicalArticleField.isEmpty()){ + caseClinicalArticleDao.inc(Long.valueOf(articleId),caseClinicalArticleField,num); + } + statsCaseClinicalDao.inc(1L,statsCaseClinicalField,num); + + return true; + } catch (Exception e) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return false; + } + } + + /** + * 减少文章的统计字段 + * @param articleId 文章id + * @param type 类型:1:阅读量 2:收藏量 3:评论数 4:文章数 + */ + public boolean DecClinicalArticleStats(String articleId,Integer type,Integer num){ + try { + String caseClinicalArticleField = ""; // 具体文章 + String statsCaseClinicalField = ""; // 全部文章 + + // 阅读 + if (type == 1){ + caseClinicalArticleField = "read_num"; // 具体文章 + statsCaseClinicalField = "article_read_num"; // 全部文章 + } + + // 收藏 + if (type == 2){ + caseClinicalArticleField = "collect_num"; // 具体文章 + statsCaseClinicalField = "article_collect_num"; // 全部文章 + } + + // 评论 + if (type == 3){ + caseClinicalArticleField = "comment_num"; // 具体文章 + statsCaseClinicalField = "article_comment_num"; // 全部文章 + } + + // 文章数 + if (type == 4){ + statsCaseClinicalField = "article_num"; // 全部文章 + } + + if (!caseClinicalArticleField.isEmpty()){ + caseClinicalArticleDao.dec(Long.valueOf(articleId),caseClinicalArticleField,num); + } + statsCaseClinicalDao.dec(1L,statsCaseClinicalField,num); + + return true; + } catch (Exception e) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return false; + } + } + + // 处理文章作者 + public void HandleArticleAuthor(CaseClinicalArticleEntity caseClinicalArticle,List r,byte[] qrCodeBytes){ + // 需新增的 + List addList = new ArrayList<>(); + + // 需删除的 + List deleteList = new ArrayList<>(); + + // 获取全部作者 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalArticleAuthorEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleAuthors = caseClinicalArticleAuthorDao.selectList(authorQueryWrapper); + + // 处理新增的情况 + for (CaseClinicalArticleAuthorForm a : r){ + // 默认本条为新增 + boolean exists = true; + for (CaseClinicalArticleAuthorEntity b : caseClinicalArticleAuthors){ + if (Objects.equals(a.getDoctorId(), b.getDoctorId())){ + exists = false; + break; // 已存在,跳出内层循环 + } + } + + if (exists) { + addList.add(a); // 不存在于旧数据中,加入新增列表 + } + } + + // 处理删除的情况 + for (CaseClinicalArticleAuthorEntity b : caseClinicalArticleAuthors){ + // 默认本条为删除 + boolean exists = true; + for (CaseClinicalArticleAuthorForm a : r){ + if (Objects.equals(a.getDoctorId(), b.getDoctorId())){ + exists = false; + break; // 已存在,跳出内层循环 + } + } + + if (exists) { + deleteList.add(b); // 加入删除列表 + } + } + + // 删除 + for (CaseClinicalArticleAuthorEntity author : deleteList){ + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId, author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("操作失败"); + } + + // 获取医院数据 + BasicHospitalEntity basicHospital = basicHospitalDao.selectById(caseClinicalDoctor.getHospitalId()); + if (basicHospital == null) { + throw new BusinessException("操作失败"); + } + + // 减少作者统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(caseClinicalDoctor.getDoctorId()),1); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),1); + + // 删除该作者 + caseClinicalArticleAuthorDao.deleteById(author.getAuthorId()); + + // 删除该作者证书 + LambdaQueryWrapper certWrapper = new LambdaQueryWrapper<>(); + certWrapper.eq(CaseClinicalDoctorCertEntity::getDoctorId, caseClinicalDoctor.getDoctorId()); + certWrapper.eq(CaseClinicalDoctorCertEntity::getId, caseClinicalArticle.getArticleId()); + certWrapper.eq(CaseClinicalDoctorCertEntity::getType, 1); + caseClinicalDoctorCertDao.delete(certWrapper); + } + + // 新增新的作者 + for (CaseClinicalArticleAuthorForm author : addList){ + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectById(author.getDoctorId()); + + CaseClinicalArticleAuthorEntity caseClinicalArticleAuthor = new CaseClinicalArticleAuthorEntity(); + caseClinicalArticleAuthor.setArticleId(caseClinicalArticle.getArticleId()); + caseClinicalArticleAuthor.setDoctorId(caseClinicalDoctor.getDoctorId()); + caseClinicalArticleAuthorDao.insert(caseClinicalArticleAuthor); + + LocalDateTime lastPushDate = caseClinicalArticleDao.selectLastArticlePushDateByDoctorId(caseClinicalDoctor.getDoctorId()); + + // 新增作者统计 + caseClinicalService.IncStatsCaseClinicalDoctor(String.valueOf(caseClinicalDoctor.getDoctorId()),1,lastPushDate); + + // 新增医院统计 + caseClinicalService.IncStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),1,lastPushDate); + + // 生成用户证书-文章/视频 + if (qrCodeBytes == null || qrCodeBytes.length == 0) { + // 生成二维码图片 + if (caseClinicalArticle.getShareQrcode() == null){ + try { + // 生成用户分享二维码-文章/视频 + qrCodeBytes = addUnlimitedQrcode(caseClinicalArticle.getArticleId()); + } catch (Exception e) { + // 不处理 + throw new BusinessException("操作失败"); + } + }else{ + // 下载二维码图片 + qrCodeBytes = Oss.getObjectToByte(caseClinicalArticle.getShareQrcode().replaceFirst("^/+", "")); + if (qrCodeBytes == null) { + throw new BusinessException("操作失败"); + } + } + } + + // 下载头像 + byte[] avatarByte = new byte[0]; + if (caseClinicalDoctor.getAvatar() != null && !caseClinicalDoctor.getAvatar().isEmpty()) { + avatarByte = Oss.getObjectToByte(caseClinicalDoctor.getAvatar().replaceFirst("^/+", "")); + }else{ + try { + avatarByte = ImageUtil.readImageToBytes("static/cert/avatar.png"); + } catch (Exception e) { + throw new BusinessException(e.getMessage()); + } + } + + if (avatarByte == null) { + throw new BusinessException("操作失败"); + } + + userService.CreateUserCert( + String.valueOf(caseClinicalArticle.getArticleId()), + 1, + String.valueOf(caseClinicalDoctor.getDoctorId()), + qrCodeBytes, + avatarByte + ); + } + } + + // 处理文章标签 + public void HandleArticleLabel(CaseClinicalArticleEntity caseClinicalArticle, List r){ + // 获取全部b标签 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalArticleLabelEntity::getArticleId, caseClinicalArticle.getArticleId()); + List caseClinicalArticleLabels = caseClinicalArticleLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalArticleLabelEntity label : caseClinicalArticleLabels){ + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(),1); + + // 删除视频标签 + caseClinicalArticleLabelDao.deleteById(label.getArticleLabelId()); + } + + for (CaseClinicalArticleLabelForm label : r){ + CaseClinicalArticleLabelEntity caseClinicalArticleLabel = new CaseClinicalArticleLabelEntity(); + caseClinicalArticleLabel.setArticleId(caseClinicalArticle.getArticleId()); + caseClinicalArticleLabel.setAppIden(label.getAppIden()); + caseClinicalArticleLabel.setLabelName(label.getLabelName()); + caseClinicalArticleLabelDao.insert(caseClinicalArticleLabel); + + LocalDateTime lastPushDate = caseClinicalArticleDao.selectLastArticlePushDateByLabelId(label.getAppIden()); + + // 新增标签统计 + caseClinicalService.IncStatsCaseClinicalLabel(label.getAppIden(),caseClinicalArticleLabel.getLabelName(),1,lastPushDate); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/controller/CaseClinicalArticleAuthorController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/controller/CaseClinicalArticleAuthorController.java new file mode 100644 index 0000000..2b31a40 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/controller/CaseClinicalArticleAuthorController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.controller; + +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.form.CaseClinicalArticleAuthorQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo.CaseClinicalArticleAuthorVO; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.service.CaseClinicalArticleAuthorService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 病例库-临床-文章-作者 Controller + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "病例库-临床-文章-作者") +public class CaseClinicalArticleAuthorController { + + @Resource + private CaseClinicalArticleAuthorService caseClinicalArticleAuthorService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/caseClinicalArticleAuthor/queryPage") + @SaCheckPermission("caseClinicalArticleAuthor:query") + public ResponseDTO> queryPage(@RequestBody @Valid CaseClinicalArticleAuthorQueryForm queryForm) { + return ResponseDTO.ok(caseClinicalArticleAuthorService.queryPage(queryForm)); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/dao/CaseClinicalArticleAuthorDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/dao/CaseClinicalArticleAuthorDao.java new file mode 100644 index 0000000..43e6560 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/dao/CaseClinicalArticleAuthorDao.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.entity.CaseClinicalArticleAuthorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.form.CaseClinicalArticleAuthorQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo.CaseClinicalArticleAuthorVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 病例库-临床-文章-作者 Dao + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ + +@Mapper +public interface CaseClinicalArticleAuthorDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") CaseClinicalArticleAuthorQueryForm queryForm); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/entity/CaseClinicalArticleAuthorEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/entity/CaseClinicalArticleAuthorEntity.java new file mode 100644 index 0000000..fe0ff67 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/entity/CaseClinicalArticleAuthorEntity.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; + +/** + * 病例库-临床-文章-作者 实体类 + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ + +@Data +@TableName("case_clinical_article_author") +public class CaseClinicalArticleAuthorEntity { + + /** + * 主键id + */ + @TableId + private Long authorId; + + /** + * 临床文章id + */ + private Long articleId; + + /** + * 医生id + */ + private Long doctorId; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + + /** + * 医生数据 + */ + @TableField(exist = false) + private CaseClinicalDoctorEntity caseClinicalDoctor; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/form/CaseClinicalArticleAuthorQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/form/CaseClinicalArticleAuthorQueryForm.java new file mode 100644 index 0000000..c9e5448 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/form/CaseClinicalArticleAuthorQueryForm.java @@ -0,0 +1,19 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 病例库-临床-文章-作者 分页查询表单 + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseClinicalArticleAuthorQueryForm extends PageParam { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/vo/CaseClinicalArticleAuthorVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/vo/CaseClinicalArticleAuthorVO.java new file mode 100644 index 0000000..2edfe6c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/domain/vo/CaseClinicalArticleAuthorVO.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo; + +import cn.hutool.core.bean.BeanUtil; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.entity.CaseClinicalArticleAuthorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; + +/** + * 病例库-临床-文章-作者 列表VO + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalArticleAuthorVO { + @Schema(description = "主键id") + private Long authorId; + + @Schema(description = "临床文章id") + private Long articleId; + + @Schema(description = "医生id") + private Long doctorId; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + + @Schema(description = "医生数据") + private CaseClinicalDoctorVO caseClinicalDoctor; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/manager/CaseClinicalArticleAuthorManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/manager/CaseClinicalArticleAuthorManager.java new file mode 100644 index 0000000..763a18e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/manager/CaseClinicalArticleAuthorManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.manager; + +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.entity.CaseClinicalArticleAuthorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.dao.CaseClinicalArticleAuthorDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 病例库-临床-文章-作者 Manager + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ +@Service +public class CaseClinicalArticleAuthorManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/service/CaseClinicalArticleAuthorService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/service/CaseClinicalArticleAuthorService.java new file mode 100644 index 0000000..d695b9d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalArticleAuthor/service/CaseClinicalArticleAuthorService.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.dao.CaseClinicalArticleAuthorDao; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.entity.CaseClinicalArticleAuthorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.form.CaseClinicalArticleAuthorQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo.CaseClinicalArticleAuthorVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 病例库-临床-文章-作者 Service + * + * @Author xing + * @Date 2025-08-05 08:45:33 + * @Copyright gdxz + */ + +@Service +public class CaseClinicalArticleAuthorService { + + @Resource + private CaseClinicalArticleAuthorDao caseClinicalArticleAuthorDao; + + /** + * 分页查询 + */ + public PageResult queryPage(CaseClinicalArticleAuthorQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = caseClinicalArticleAuthorDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/controller/CaseClinicalDoctorController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/controller/CaseClinicalDoctorController.java new file mode 100644 index 0000000..1f6ae9e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/controller/CaseClinicalDoctorController.java @@ -0,0 +1,105 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.controller; + +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorAddForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorQueryListForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorUpdateForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorStatusUpdateForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.AppDoctorVO; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.service.CaseClinicalDoctorService; +import net.lab1024.sa.base.common.domain.ValidateList; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * 医生管理 Controller + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "医生管理") +public class CaseClinicalDoctorController { + + @Resource + private CaseClinicalDoctorService caseClinicalDoctorService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/caseClinicalDoctor/queryPage") + @SaCheckPermission("caseClinicalDoctor:query") + public ResponseDTO> queryPage(@RequestBody @Valid CaseClinicalDoctorQueryForm queryForm) { + return ResponseDTO.ok(caseClinicalDoctorService.queryPage(queryForm)); + } + + @Operation(summary = "列表查询 @author xing") + @PostMapping("/caseClinicalDoctor/queryList") + @SaCheckPermission("caseClinicalDoctor:query") + public ResponseDTO> queryList(@RequestBody @Valid CaseClinicalDoctorQueryListForm queryForm) { + return ResponseDTO.ok(caseClinicalDoctorService.queryList(queryForm)); + } + + @Operation(summary = "添加 @author xing") + @PostMapping("/caseClinicalDoctor/add") + @SaCheckPermission("caseClinicalDoctor:add") + public ResponseDTO add(@RequestBody @Valid CaseClinicalDoctorAddForm addForm) { + return caseClinicalDoctorService.add(addForm); + } + + @Operation(summary = "更新 @author xing") + @PostMapping("/caseClinicalDoctor/update") + @SaCheckPermission("caseClinicalDoctor:update") + public ResponseDTO update(@RequestBody @Valid CaseClinicalDoctorUpdateForm updateForm) { + return caseClinicalDoctorService.update(updateForm); + } + + @Operation(summary = "批量删除 @author xing") + @PostMapping("/caseClinicalDoctor/batchDelete") + @SaCheckPermission("caseClinicalDoctor:delete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return caseClinicalDoctorService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author xing") + @GetMapping("/caseClinicalDoctor/delete/{doctorId}") + @SaCheckPermission("caseClinicalDoctor:delete") + public ResponseDTO batchDelete(@PathVariable Long doctorId) { + return caseClinicalDoctorService.delete(doctorId); + } + + @Operation(summary = "更新状态 @author xing") + @PostMapping("/caseClinicalDoctor/status/update") + @SaCheckPermission("caseClinicalDoctor:update") + public ResponseDTO updateStatus(@RequestBody @Valid CaseClinicalDoctorStatusUpdateForm updateForm) { + return caseClinicalDoctorService.updateStatus(updateForm.getDoctorId(), updateForm.getStatus()); + } + + @Operation(summary = "获取APP医生信息 @author xing") + @GetMapping("/caseClinicalDoctor/getAppDoctor") + @SaCheckPermission("caseClinicalDoctor:query") + public ResponseDTO getAppDoctor(@RequestParam String doctorName) { + return caseClinicalDoctorService.getAppDoctor(doctorName); + } + + @Operation(summary = "获取医生详情 @author xing") + @GetMapping("/caseClinicalDoctor/getDetail/{doctorId}") + @SaCheckPermission("caseClinicalDoctor:query") + public ResponseDTO getDetail(@PathVariable Long doctorId) { + return caseClinicalDoctorService.getDetail(doctorId); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/dao/CaseClinicalDoctorCertDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/dao/CaseClinicalDoctorCertDao.java new file mode 100644 index 0000000..7c1e33e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/dao/CaseClinicalDoctorCertDao.java @@ -0,0 +1,24 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorCertEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorCertVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 医生证书 Dao + * + * @Author xing + * @Date 2025-08-06 11:22:22 + * @Copyright gdxz + */ + +@Mapper +public interface CaseClinicalDoctorCertDao extends BaseMapper { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/dao/CaseClinicalDoctorDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/dao/CaseClinicalDoctorDao.java new file mode 100644 index 0000000..b0feca0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/dao/CaseClinicalDoctorDao.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorQueryListForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 医生管理 Dao + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@Mapper +public interface CaseClinicalDoctorDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") CaseClinicalDoctorQueryForm queryForm); + + /** + * 列表 查询 + * + * @param queryForm + * @return + */ + List queryList(@Param("queryForm") CaseClinicalDoctorQueryListForm queryForm); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/entity/CaseClinicalDoctorCertEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/entity/CaseClinicalDoctorCertEntity.java new file mode 100644 index 0000000..64192bf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/entity/CaseClinicalDoctorCertEntity.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 医生证书 实体类 + * + * @Author xing + * @Date 2025-08-06 11:22:22 + * @Copyright gdxz + */ + +@Data +@TableName("case_clinical_doctor_cert") +public class CaseClinicalDoctorCertEntity { + + /** + * 主键id + */ + @TableId + private Long certId; + + /** + * 医生id + */ + private Long doctorId; + + /** + * 关联的视频/文章id + */ + private Long id; + + /** + * 类型(1:文章 2:视频) + */ + private Integer type; + + /** + * 证书图片 + */ + private String certImage; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/entity/CaseClinicalDoctorEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/entity/CaseClinicalDoctorEntity.java new file mode 100644 index 0000000..33aeb3b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/entity/CaseClinicalDoctorEntity.java @@ -0,0 +1,69 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; + +/** + * 医生管理 实体类 + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@Data +@TableName("case_clinical_doctor") +public class CaseClinicalDoctorEntity { + + /** + * 主键id + */ + @TableId + private Long doctorId; + + /** + * app唯一标识(存在即表示为注册用户) + */ + private String doctorIden; + + /** + * 用户名称 + */ + private String doctorName; + + /** + * 所属医院id + */ + private Long hospitalId; + + /** + * 状态(1:正常 2:禁用) + */ + private Integer status; + + /** + * 头像 + */ + private String avatar; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + + /** + * 医院数据 + */ + @TableField(exist = false) + private BasicHospitalEntity basicHospital; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorAddForm.java new file mode 100644 index 0000000..b597b92 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorAddForm.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form; + +import com.fasterxml.jackson.annotation.JsonAlias; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.base.common.json.deserializer.FileKeyVoDeserializer; + +/** + * 医生管理 新建表单 + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalDoctorAddForm { + + @Schema(description = "用户名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "用户名称 不能为空") + private String doctorName; + + @Schema(description = "app唯一标识(可用uuid入参)") + @JsonAlias({"uuid"}) + private String doctorIden; + + @Schema(description = "所属医院id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "所属医院id 不能为空") + private Long hospitalId; + + @Schema(description = "医院UUID") + private String hospitalUuid; + + @Schema(description = "状态(1:正常 2:禁用)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态(1:正常 2:禁用) 不能为空") + private Integer status = 1; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorQueryForm.java new file mode 100644 index 0000000..b1e88c6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorQueryForm.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 医生管理 分页查询表单 + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseClinicalDoctorQueryForm extends PageParam { + + @Schema(description = "医生姓名") + private String keywords; + + @Schema(description = "医院名称") + private String hospitalName; + + @Schema(description = "状态") + private Integer status; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorQueryListForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorQueryListForm.java new file mode 100644 index 0000000..e055049 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorQueryListForm.java @@ -0,0 +1,23 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import net.lab1024.sa.base.common.domain.PageParam; + +/** + * 医生管理 分页查询表单 + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalDoctorQueryListForm { + @Schema(description = "医生姓名") + private String keywords; + + @Schema(description = "数量") + private Integer limit = 10; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorStatusUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorStatusUpdateForm.java new file mode 100644 index 0000000..a57f2be --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorStatusUpdateForm.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +/** + * 医生管理 状态更新表单 + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ +@Data +@Schema(description = "医生管理 状态更新表单") +public class CaseClinicalDoctorStatusUpdateForm { + + @Schema(description = "医生ID") + @NotNull(message = "医生ID不能为空") + private Long doctorId; + + @Schema(description = "状态 1:正常 2:禁用") + @NotNull(message = "状态不能为空") + private Integer status; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorUpdateForm.java new file mode 100644 index 0000000..c3fd9b9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/form/CaseClinicalDoctorUpdateForm.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.base.common.json.deserializer.FileKeyVoDeserializer; + +/** + * 医生管理 更新表单 + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalDoctorUpdateForm { + + @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "主键id 不能为空") + private Long doctorId; + + @Schema(description = "用户名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "用户名称 不能为空") + private String doctorName; + + @Schema(description = "状态(1:正常 2:禁用)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态(1:正常 2:禁用) 不能为空") + private Integer status; + + @Schema(description = "头像", requiredMode = Schema.RequiredMode.REQUIRED) + @JsonDeserialize(using = FileKeyVoDeserializer.class) + private String avatar; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/AppDoctorVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/AppDoctorVO.java new file mode 100644 index 0000000..7e9be40 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/AppDoctorVO.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * APP医生信息 VO + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ +@Data +@Schema(description = "APP医生信息") +public class AppDoctorVO { + + @Schema(description = "UUID") + private String uuid; + + @Schema(description = "姓名") + private String doctorName; + + @Schema(description = "手机号") + private String phone; + + @Schema(description = "省份") + private String province; + + @Schema(description = "医院UUID") + private String hospitalUuid; + + @Schema(description = "医院ID") + private Long hospitalId; + + @Schema(description = "医院名称") + private String hospitalName; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/CaseClinicalDoctorCertVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/CaseClinicalDoctorCertVO.java new file mode 100644 index 0000000..d0700cf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/CaseClinicalDoctorCertVO.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 医生证书 列表VO + * + * @Author xing + * @Date 2025-08-06 11:22:22 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalDoctorCertVO { + + + @Schema(description = "主键id") + private Long certId; + + @Schema(description = "医生id") + private Long doctorId; + + @Schema(description = "关联的视频/文章id") + private Long id; + + @Schema(description = "类型(1:文章 2:视频)") + private Integer type; + + @Schema(description = "证书图片") + private String certImage; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/CaseClinicalDoctorVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/CaseClinicalDoctorVO.java new file mode 100644 index 0000000..2cc86f9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/domain/vo/CaseClinicalDoctorVO.java @@ -0,0 +1,58 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo; + +import cn.hutool.core.bean.BeanUtil; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer; + +/** + * 医生管理 列表VO + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalDoctorVO { + @Schema(description = "主键id") + private Long doctorId; + + @Schema(description = "app唯一标识(存在即表示为注册用户)") + private String doctorIden; + + @Schema(description = "用户名称") + private String doctorName; + + @Schema(description = "所属医院id") + private Long hospitalId; + + @Schema(description = "所属医院名称") + private String hospitalName; + + @Schema(description = "所属医院省份") + private String hospitalProvince; + + @Schema(description = "所属医院城市") + private String hospitalCity; + + @Schema(description = "状态(1:正常 2:禁用)") + private Integer status; + + @Schema(description = "头像") + @JsonSerialize(using = FileKeyVoSerializer.class) + private String avatar; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/manager/CaseClinicalDoctorCertManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/manager/CaseClinicalDoctorCertManager.java new file mode 100644 index 0000000..b520938 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/manager/CaseClinicalDoctorCertManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.manager; + +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorCertDao; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorCertEntity; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 医生证书 Manager + * + * @Author xing + * @Date 2025-08-06 11:22:22 + * @Copyright gdxz + */ +@Service +public class CaseClinicalDoctorCertManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/manager/CaseClinicalDoctorManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/manager/CaseClinicalDoctorManager.java new file mode 100644 index 0000000..4936e55 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/manager/CaseClinicalDoctorManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.manager; + +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 医生管理 Manager + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ +@Service +public class CaseClinicalDoctorManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/service/CaseClinicalDoctorCertService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/service/CaseClinicalDoctorCertService.java new file mode 100644 index 0000000..e2ff1b2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/service/CaseClinicalDoctorCertService.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorCertDao; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorCertEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorCertVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 医生证书 Service + * + * @Author xing + * @Date 2025-08-06 11:22:22 + * @Copyright gdxz + */ + +@Service +public class CaseClinicalDoctorCertService { + + @Resource + private CaseClinicalDoctorCertDao caseClinicalDoctorCertDao; + + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/service/CaseClinicalDoctorService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/service/CaseClinicalDoctorService.java new file mode 100644 index 0000000..bd9dc33 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalDoctor/service/CaseClinicalDoctorService.java @@ -0,0 +1,437 @@ +package net.lab1024.sa.admin.module.business.caseClinicalDoctor.service; + +import java.util.List; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorDao; +import net.lab1024.sa.admin.module.business.basicHospital.dao.BasicHospitalDao; +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorAddForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorQueryListForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.form.CaseClinicalDoctorUpdateForm; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.AppDoctorVO; +import net.lab1024.sa.admin.module.business.user.service.UserService; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.admin.extend.app.UserInfo.UserInfo; +import net.lab1024.sa.admin.extend.app.UserInfo.GetUserInfoResponse; +import net.lab1024.sa.admin.extend.app.Hospital.Hospital; +import net.lab1024.sa.admin.extend.app.Hospital.GetHospitalByUuidResponse; +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import jakarta.annotation.Resource; + +import static com.baomidou.mybatisplus.extension.toolkit.Db.save; + +/** + * 医生管理 Service + * + * @Author xing + * @Date 2025-08-04 15:24:56 + * @Copyright gdxz + */ + +@Slf4j +@Service +public class CaseClinicalDoctorService { + + @Resource + private CaseClinicalDoctorDao caseClinicalDoctorDao; + + @Resource + private BasicHospitalDao basicHospitalDao; + + @Resource + private UserInfo userInfo; + + @Resource + private Hospital hospital; + + @Resource + private UserService userService; + + /** + * 分页查询 + */ + public PageResult queryPage(CaseClinicalDoctorQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = caseClinicalDoctorDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 列表查询 + */ + public List queryList(CaseClinicalDoctorQueryListForm queryForm) { + List list = caseClinicalDoctorDao.queryList(queryForm); + + // 为每个医生VO设置医院信息 + for (CaseClinicalDoctorVO vo : list) { + if (vo.getHospitalId() != null) { + BasicHospitalEntity basicHospital = basicHospitalDao.selectById(vo.getHospitalId()); + if (basicHospital != null) { + vo.setHospitalName(basicHospital.getHospitalName()); + vo.setHospitalProvince(basicHospital.getProvince()); + vo.setHospitalCity(basicHospital.getCity()); + } + } + } + + return list; + } + + /** + * 添加 + */ + public ResponseDTO add(CaseClinicalDoctorAddForm addForm) { + // 若传入了医生的 uuid(doctorIden),则优先使用 uuid 从APP获取医生数据,然后按本地是否存在做新增/更新 + if (addForm.getDoctorIden() != null && !addForm.getDoctorIden().trim().isEmpty()) { + // 通过 uuid 调用 app 接口获取医生数据 + GetUserInfoResponse userInfoByUuid = userInfo.getUserInfoByUuid(addForm.getDoctorIden()); + if (userInfoByUuid == null || userInfoByUuid.getData() == null) { + throw new BusinessException("获取医生信息失败"); + } + + GetUserInfoResponse.ResponsData data = userInfoByUuid.getData(); + Long targetHospitalId = addForm.getHospitalId(); + + // 先按 uuid 匹配本地医生 + LambdaQueryWrapper doctorWrapper = new LambdaQueryWrapper<>(); + doctorWrapper.eq(CaseClinicalDoctorEntity::getDoctorIden, data.getUuid()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorWrapper); + + // 二次匹配:姓名 + 医院 + if (caseClinicalDoctor == null) { + doctorWrapper = new LambdaQueryWrapper<>(); + doctorWrapper.eq(CaseClinicalDoctorEntity::getDoctorName, data.getRealname()); + doctorWrapper.eq(CaseClinicalDoctorEntity::getHospitalId, targetHospitalId); + caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorWrapper); + } + + if (caseClinicalDoctor == null) { + // 新增 + CaseClinicalDoctorEntity entity = new CaseClinicalDoctorEntity(); + entity.setDoctorName(data.getRealname()); + entity.setDoctorIden(data.getUuid()); + entity.setHospitalId(targetHospitalId); + entity.setStatus(addForm.getStatus() == null ? 1 : addForm.getStatus()); + if (data.getPhoto() != null) { + try { + String ossPath = userService.handleUserImage(data.getImg_host() + data.getPhoto()); + entity.setAvatar(ossPath); + } catch (Exception ignore) { + entity.setAvatar(""); + } + } else { + entity.setAvatar(""); + } + caseClinicalDoctorDao.insert(entity); + return ResponseDTO.ok(); + } + + // 更新对比 + boolean needUpdate = false; + if (!Objects.equals(caseClinicalDoctor.getDoctorName(), data.getRealname())) { + caseClinicalDoctor.setDoctorName(data.getRealname()); + needUpdate = true; + } + if (!Objects.equals(targetHospitalId, caseClinicalDoctor.getHospitalId())) { + caseClinicalDoctor.setHospitalId(targetHospitalId); + needUpdate = true; + } + if (!Objects.equals(data.getUuid(), caseClinicalDoctor.getDoctorIden())) { + caseClinicalDoctor.setDoctorIden(data.getUuid()); + needUpdate = true; + } + if (data.getPhoto() != null) { + try { + String ossPath = userService.handleUserImage(data.getImg_host() + data.getPhoto()); + caseClinicalDoctor.setAvatar(ossPath); + needUpdate = true; + } catch (Exception ignore) { + // 不处理 + } + } + + if (needUpdate) { + caseClinicalDoctorDao.updateById(caseClinicalDoctor); + } + return ResponseDTO.ok(); + } + + // 没有 uuid 时,按表单直接新增 + CaseClinicalDoctorEntity caseClinicalDoctorEntity = SmartBeanUtil.copy(addForm, CaseClinicalDoctorEntity.class); + caseClinicalDoctorDao.insert(caseClinicalDoctorEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + */ + public ResponseDTO update(CaseClinicalDoctorUpdateForm updateForm) { + CaseClinicalDoctorEntity caseClinicalDoctorEntity = SmartBeanUtil.copy(updateForm, CaseClinicalDoctorEntity.class); + caseClinicalDoctorDao.updateById(caseClinicalDoctorEntity); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + */ + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)){ + return ResponseDTO.ok(); + } + + caseClinicalDoctorDao.deleteBatchIds(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + */ + public ResponseDTO delete(Long doctorId) { + if (null == doctorId){ + return ResponseDTO.ok(); + } + + caseClinicalDoctorDao.deleteById(doctorId); + return ResponseDTO.ok(); + } + + /** + * 更新状态 + */ + public ResponseDTO updateStatus(Long doctorId, Integer status) { + if (null == doctorId) { + return ResponseDTO.userErrorParam("医生ID不能为空"); + } + + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectById(doctorId); + if (caseClinicalDoctor == null) { + return ResponseDTO.userErrorParam("医生不存在"); + } + + // 如果状态没有变化,直接返回 + if (Objects.equals(caseClinicalDoctor.getStatus(), status)) { + return ResponseDTO.ok(); + } + + // 更新状态 + caseClinicalDoctor.setStatus(status); + caseClinicalDoctorDao.updateById(caseClinicalDoctor); + + return ResponseDTO.ok(); + } + + /** + * 获取APP医生信息 + */ + @Transactional + public ResponseDTO getAppDoctor(String doctorName) { + if (doctorName == null || doctorName.trim().isEmpty()) { + return ResponseDTO.userErrorParam("医生姓名不能为空"); + } + + // 调用UserInfo获取医生信息 + GetUserInfoResponse userInfoResponse = userInfo.getUserInfoByName(doctorName); + + if (userInfoResponse == null || userInfoResponse.getData() == null) { + throw new BusinessException("未找到医生信息"); + } + + if (userInfoResponse.getData().getUuid() == null) { + throw new BusinessException("未找到医生信息"); + } + + GetUserInfoResponse.ResponsData userData = userInfoResponse.getData(); + + // 转换为AppDoctorVO + AppDoctorVO appDoctor = new AppDoctorVO(); + appDoctor.setUuid(userData.getUuid()); + appDoctor.setDoctorName(userData.getRealname()); + appDoctor.setPhone(userData.getMobile()); + appDoctor.setProvince(userData.getProvName()); + appDoctor.setHospitalUuid(userData.getHospitalUuid()); + + // 如果存在hospitalUuid,检查并获取医院信息 + if (userData.getHospitalUuid() != null && !userData.getHospitalUuid().trim().isEmpty()) { + // 先查询数据库中是否已存在该医院 + LambdaQueryWrapper hospitalQueryWrapper = new LambdaQueryWrapper<>(); + hospitalQueryWrapper.eq(BasicHospitalEntity::getHospitalIden, userData.getHospitalUuid()); + BasicHospitalEntity existingHospital = basicHospitalDao.selectOne(hospitalQueryWrapper); + + if (existingHospital != null) { + // 医院已存在,设置hospitalId和hospitalName + appDoctor.setHospitalId(existingHospital.getHospitalId()); + appDoctor.setHospitalName(existingHospital.getHospitalName()); + } else { + // 医院不存在,调用API获取医院信息并存储 + GetHospitalByUuidResponse hospitalResponse = hospital.getHospitalByUuid(userData.getHospitalUuid()); + + if (hospitalResponse == null || hospitalResponse.getData() == null) { + throw new BusinessException("获取医院信息失败:医院数据为空"); + } + + GetHospitalByUuidResponse.GetHospitalByUuidData hospitalData = hospitalResponse.getData(); + + // 创建新的医院实体 + BasicHospitalEntity newHospital = new BasicHospitalEntity(); + newHospital.setHospitalIden(hospitalData.getUuid()); + newHospital.setHospitalName(hospitalData.getName()); + newHospital.setHospitalLevel(hospitalData.getLevel()); + newHospital.setProvince(hospitalData.getProv_name()); + newHospital.setCity(hospitalData.getCity_name()); + newHospital.setDoctorNumber(hospitalData.getExpert_num()); + newHospital.setSource(2); // 默认来源为肝胆相照 + + // 插入医院数据 + basicHospitalDao.insert(newHospital); + + // 设置返回的hospitalId和hospitalName + appDoctor.setHospitalId(newHospital.getHospitalId()); + appDoctor.setHospitalName(newHospital.getHospitalName()); + } + } else { + // 没有hospitalUuid,设置为null + appDoctor.setHospitalId(null); + appDoctor.setHospitalName(null); + } + + return ResponseDTO.ok(appDoctor); + } + + /** + * 获取医生详情 + */ + public ResponseDTO getDetail(Long doctorId) { + if (null == doctorId) { + return ResponseDTO.userErrorParam("医生ID不能为空"); + } + + CaseClinicalDoctorEntity entity = caseClinicalDoctorDao.selectById(doctorId); + if (entity == null) { + return ResponseDTO.userErrorParam("医生不存在"); + } + + CaseClinicalDoctorVO vo = SmartBeanUtil.copy(entity, CaseClinicalDoctorVO.class); + + // 设置医院信息 + if (vo.getHospitalId() != null) { + BasicHospitalEntity basicHospital = basicHospitalDao.selectById(vo.getHospitalId()); + if (basicHospital != null) { + vo.setHospitalName(basicHospital.getHospitalName()); + vo.setHospitalProvince(basicHospital.getProvince()); + vo.setHospitalCity(basicHospital.getCity()); + } + } + + return ResponseDTO.ok(vo); + } + +// /** +// * 获取app医生数据 +// * @return UserEntity +// */ +// public CaseClinicalDoctorEntity GetAppCaseClinicalDoctor(GetUserInfoResponse r) throws BusinessException { +// GetUserInfoResponse.ResponsData data = r.getData(); +// +// // 获取app医院数据 +// BasicHospitalEntity basicHospital = GetAppHospital(data.getHospitalUuid()); +// +// // 获取对应医生数据 +// LambdaQueryWrapper caseClinicalDoctorWrapper = new LambdaQueryWrapper<>(); +// caseClinicalDoctorWrapper.eq(CaseClinicalDoctorEntity::getDoctorIden, data.getUuid()); +// CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(caseClinicalDoctorWrapper); +// if (caseClinicalDoctor == null){ +// // 二次匹配:通过姓名-医院获取医生信息 +// caseClinicalDoctorWrapper = new LambdaQueryWrapper<>(); +// caseClinicalDoctorWrapper.eq(CaseClinicalDoctorEntity::getDoctorName, data.getRealname()); +// caseClinicalDoctorWrapper.eq(CaseClinicalDoctorEntity::getHospitalId, basicHospital.getHospitalId()); +// caseClinicalDoctor = caseClinicalDoctorDao.selectOne(caseClinicalDoctorWrapper); +// } +// +// if (caseClinicalDoctor == null){ +// caseClinicalDoctor = new CaseClinicalDoctorEntity(); +// caseClinicalDoctor.setDoctorName(data.getRealname()); +// caseClinicalDoctor.setDoctorIden(data.getUuid()); +// caseClinicalDoctor.setHospitalId(basicHospital.getHospitalId()); +// if (data.getPhoto() != null) { +// String ossPath = userService.handleUserImage(data.getImg_host() + data.getPhoto()); +// caseClinicalDoctor.setAvatar(ossPath); +// }else{ +// caseClinicalDoctor.setAvatar(""); +// } +// int res = caseClinicalDoctorDao.insert(caseClinicalDoctor); +// if (res <= 0){ +// throw new BusinessException("操作失败"); +// } +// }else{ +// if (!Objects.equals(caseClinicalDoctor.getDoctorName(), data.getRealname())){ +// caseClinicalDoctor.setDoctorName(data.getRealname()); +// } +// +// if (!Objects.equals(basicHospital.getHospitalId(), caseClinicalDoctor.getHospitalId())){ +// caseClinicalDoctor.setHospitalId(basicHospital.getHospitalId()); +// } +// +// if (!Objects.equals(data.getUuid(), caseClinicalDoctor.getDoctorIden())){ +// caseClinicalDoctor.setDoctorIden(data.getUuid()); +// } +// +// if (data.getPhoto() != null) { +// try { +// String ossPath = userService.handleUserImage(data.getImg_host() + data.getPhoto()); +// caseClinicalDoctor.setAvatar(ossPath); +// }catch (Exception e){ +// // 不处理 +// } +// } +// +// caseClinicalDoctorDao.updateById(caseClinicalDoctor); +// } +// +// return caseClinicalDoctor; +// } + + /** + * 获取app医院数据 + * @param hospitalIden app医院唯一标识 + * @return BasicHospitalEntity + */ + public BasicHospitalEntity GetAppHospital(String hospitalIden) throws BusinessException { + // 查询数据库医院信息 + LambdaQueryWrapper basicHospitalWrapper = new LambdaQueryWrapper<>(); + basicHospitalWrapper.eq(BasicHospitalEntity::getHospitalIden, hospitalIden); + BasicHospitalEntity basicHospital = basicHospitalDao.selectOne(basicHospitalWrapper); + if (basicHospital == null){ + // 请求接口获取数据 + GetHospitalByUuidResponse result = hospital.getHospitalByUuid(hospitalIden); + GetHospitalByUuidResponse.GetHospitalByUuidData data = result.getData(); + + // 构造 UserEntity 对象 + basicHospital = new BasicHospitalEntity(); + basicHospital.setHospitalIden(hospitalIden); + basicHospital.setHospitalName(data.getName()); + basicHospital.setSource(2); + basicHospital.setHospitalLevel(data.getLevel()); + basicHospital.setDoctorNumber(data.getExpert_num()); + basicHospital.setProvince(data.getProv_name()); + basicHospital.setCity(data.getCity_name()); + save(basicHospital); + } + + return basicHospital; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/controller/CaseClinicalVideoController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/controller/CaseClinicalVideoController.java new file mode 100644 index 0000000..bc33c04 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/controller/CaseClinicalVideoController.java @@ -0,0 +1,93 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.controller; + +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoAddForm; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoUpdateForm; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoStatusUpdateForm; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoVO; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.service.CaseClinicalVideoService; +import net.lab1024.sa.base.common.domain.ValidateList; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * 病例库-临床-视频 Controller + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "病例库-临床-视频") +public class CaseClinicalVideoController { + + @Resource + private CaseClinicalVideoService caseClinicalVideoService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/caseClinicalVideo/queryPage") + @SaCheckPermission("caseClinicalVideo:query") + public ResponseDTO> queryPage(@RequestBody @Valid CaseClinicalVideoQueryForm queryForm) { + return ResponseDTO.ok(caseClinicalVideoService.queryPage(queryForm)); + } + + @Operation(summary = "添加 @author xing") + @PostMapping("/caseClinicalVideo/add") + @SaCheckPermission("caseClinicalVideo:add") + public ResponseDTO add(@RequestBody @Valid CaseClinicalVideoAddForm addForm) { + return caseClinicalVideoService.add(addForm); + } + + @Operation(summary = "更新 @author xing") + @PostMapping("/caseClinicalVideo/update") + @SaCheckPermission("caseClinicalVideo:update") + public ResponseDTO update(@RequestBody @Valid CaseClinicalVideoUpdateForm updateForm) { + return caseClinicalVideoService.update(updateForm); + } + + @Operation(summary = "批量删除 @author xing") + @PostMapping("/caseClinicalVideo/batchDelete") + @SaCheckPermission("caseClinicalVideo:delete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return caseClinicalVideoService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author xing") + @GetMapping("/caseClinicalVideo/delete/{videoId}") + @SaCheckPermission("caseClinicalVideo:delete") + public ResponseDTO delete(@PathVariable Long videoId) { + return caseClinicalVideoService.delete(videoId); + } + + @Operation(summary = "生成视频分享二维码 @author xing") + @PostMapping("/caseClinicalVideo/addUnlimitedQrcode/{videoId}") + @SaCheckPermission("caseClinicalVideo:addUnlimitedQrcode") + public ResponseDTO addUnlimitedQrcode(@PathVariable Long videoId) { + caseClinicalVideoService.addUnlimitedQrcode(videoId); + return ResponseDTO.ok(); + } + + @Operation(summary = "获取视频详情 @author xing") + @GetMapping("/caseClinicalVideo/getDetail/{videoId}") + @SaCheckPermission("caseClinicalVideo:query") + public ResponseDTO getDetail(@PathVariable Long videoId) { + return caseClinicalVideoService.getDetail(videoId); + } + + @Operation(summary = "修改状态 @author xing") + @PostMapping("/caseClinicalVideo/status/update") + @SaCheckPermission("caseClinicalVideo:update") + public ResponseDTO statusUpdate(@RequestBody @Valid CaseClinicalVideoStatusUpdateForm updateForm) { + return caseClinicalVideoService.updateStatus(updateForm.getVideoId(), updateForm.getStatus()); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoAuthorDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoAuthorDao.java new file mode 100644 index 0000000..038ba90 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoAuthorDao.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.dao; + +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoAuthorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoAuthorVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 病例库-临床-视频作者 Dao + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Mapper +public interface CaseClinicalVideoAuthorDao extends BaseMapper { + + /** + * 根据视频ID查询作者列表 + * + * @param videoId + * @return + */ + List selectAuthorListByVideoId(@Param("videoId") Long videoId); + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoDao.java new file mode 100644 index 0000000..5321e21 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoDao.java @@ -0,0 +1,78 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.dao; + +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoEntity; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoQueryForm; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoVO; + +import java.time.LocalDateTime; +import java.util.List; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; + +/** + * 病例库-临床-视频 Dao + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Mapper +public interface CaseClinicalVideoDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") CaseClinicalVideoQueryForm queryForm); + + /** + * Inc 自增 + * @param videoId 视频 ID + * @param field 字段名称 + * @param numeral 增加的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical SET ${field} = ${field} + #{numeral} WHERE stats_id = #{statsId}") + int inc(@Param("statsId") Long videoId, @Param("field") String field, @Param("numeral") int numeral); + + /** + * Dec 自减 + * + * @param videoId 视频 ID + * @param field 字段名称 + * @param numeral 减少的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical " + + "SET ${field} = CASE WHEN ${field} >= #{numeral} THEN ${field} - #{numeral} ELSE 0 END " + + "WHERE stats_id = #{statsId}") + int dec(@Param("statsId") Long videoId, @Param("field") String field, @Param("numeral") int numeral); + + /** + * 根据医院ID查询该医院最后一个视频的发表时间 + * @param hospitalId 医院ID + * @return 最新发表时间,无数据时返回 null + */ + LocalDateTime selectLastVideoPushDateByHospitalId(@Param("hospitalId") Long hospitalId); + + /** + * 根据医生ID查询该医生最后一个视频的发表时间 + * @param doctorId 医生ID + * @return 最新发表时间,无数据时返回 null + */ + LocalDateTime selectLastVideoPushDateByDoctorId(@Param("doctorId") Long doctorId); + + /** + * 根据标签ID查询该标签最后一个视频的发表时间 + * @param labelIden 标签唯一标识 + * @return 最新发表时间,无数据时返回 null + */ + LocalDateTime selectLastVideoPushDateByLabelId(@Param("labelIden") String labelIden); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoLabelDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoLabelDao.java new file mode 100644 index 0000000..1af4ab2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/dao/CaseClinicalVideoLabelDao.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.dao; + +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoLabelEntity; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoLabelVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 病例库-临床-视频标签 Dao + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Mapper +public interface CaseClinicalVideoLabelDao extends BaseMapper { + + /** + * 根据视频ID查询标签列表 + * + * @param videoId + * @return + */ + List selectLabelListByVideoId(@Param("videoId") Long videoId); + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoAuthorEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoAuthorEntity.java new file mode 100644 index 0000000..84d4d18 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoAuthorEntity.java @@ -0,0 +1,54 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; + +/** + * 病例库-临床-视频作者 实体类 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +@TableName("case_clinical_video_author") +public class CaseClinicalVideoAuthorEntity { + + /** + * 主键id + */ + @TableId + private Long authorId; + + /** + * 视频id + */ + private Long videoId; + + /** + * 医生id + */ + private Long doctorId; + + /** + * 医生数据 + */ + @TableField(exist = false) + private CaseClinicalDoctorEntity caseClinicalDoctor; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoEntity.java new file mode 100644 index 0000000..8d0a7c3 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoEntity.java @@ -0,0 +1,104 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import java.util.List; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoAuthorEntity; + +/** + * 病例库-临床-视频 实体类 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +@TableName("case_clinical_video") +public class CaseClinicalVideoEntity { + + /** + * 主键id + */ + @TableId + private Long videoId; + + /** + * 标题 + */ + private String videoTitle; + + /** + * 状态(1:正常 2:禁用) + */ + private Integer videoStatus; + + /** + * 删除状态(0:否 1:是) + */ + private Integer deleteStatus; + + /** + * 阅读量 + */ + private Integer readNum; + + /** + * 收藏量 + */ + private Integer collectNum; + + /** + * 评论数 + */ + private Integer commentNum; + + /** + * 视频编号(保利) + */ + private String videoNo; + + /** + * 证书图片 + */ + private String certImage; + + /** + * 发表时间 + */ + private LocalDateTime pushDate; + + /** + * 是否外部链接(0:否 1:是) + */ + private Integer isLink; + + /** + * 外部链接地址 + */ + private String isLinkUrl; + + /** + * 分享二维码地址 + */ + private String shareQrcode; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + + // 作者 + @TableField(exist = false) + private List caseClinicalVideoAuthor; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoLabelEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoLabelEntity.java new file mode 100644 index 0000000..701efc5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/entity/CaseClinicalVideoLabelEntity.java @@ -0,0 +1,51 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-临床-视频标签 实体类 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +@TableName("case_clinical_video_label") +public class CaseClinicalVideoLabelEntity { + + /** + * 主键id + */ + @TableId + private Long videoLabelId; + + /** + * 视频id + */ + private Long videoId; + + /** + * app唯一标识 + */ + private String appIden; + + /** + * 标签名称 + */ + private String labelName; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoAddForm.java new file mode 100644 index 0000000..2fb7e94 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoAddForm.java @@ -0,0 +1,64 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import java.util.List; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo.CaseClinicalArticleAuthorVO; +import net.lab1024.sa.base.common.json.deserializer.FileKeyVoDeserializer; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoAuthorForm; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoLabelForm; + +/** + * 病例库-临床-视频 新建表单 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalVideoAddForm { + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "标题 不能为空") + private String videoTitle; + + @Schema(description = "状态(1:正常 2:禁用)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态(1:正常 2:禁用) 不能为空") + private Integer videoStatus; + + @Schema(description = "删除状态(0:否 1:是)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "删除状态(0:否 1:是) 不能为空") + private Integer deleteStatus; + + @Schema(description = "视频编号(保利)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "视频编号 不能为空") + private String videoNo; + + @Schema(description = "发表时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "发表时间 不能为空") + private LocalDateTime pushDate; + + @Schema(description = "是否外部链接(0:否 1:是)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否外部链接(0:否 1:是) 不能为空") + private Integer isLink; + + @Schema(description = "外部链接地址") + private String isLinkUrl; + + @Schema(description = "分享二维码地址") + @JsonDeserialize(using = FileKeyVoDeserializer.class) + private String shareQrcode; + + @Schema(description = "作者列表") + private List authorList; + + @Schema(description = "标签列表") + private List labelList; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoAuthorForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoAuthorForm.java new file mode 100644 index 0000000..60dedca --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoAuthorForm.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 病例库-临床-视频作者 表单 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalVideoAuthorForm { + + @Schema(description = "医生ID") + private Long doctorId; + + @Schema(description = "医生姓名") + private String doctorName; + + @Schema(description = "医院名称") + private String hospitalName; + + @Schema(description = "医院省份") + private String hospitalProvince; + + @Schema(description = "医院城市") + private String hospitalCity; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoLabelForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoLabelForm.java new file mode 100644 index 0000000..42cd3a0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoLabelForm.java @@ -0,0 +1,27 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +/** + * 病例库-临床-视频标签 表单 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalVideoLabelForm { + + @Schema(description = "医生ID") + private Long doctorId; + + @Schema(description = "唯一标识") + private String appIden; // app唯一标识 + + @Schema(description = "标签名称") + private String labelName; // 标签名称 + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoLabelQueryListForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoLabelQueryListForm.java new file mode 100644 index 0000000..0ffb9d6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoLabelQueryListForm.java @@ -0,0 +1,21 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 病例库-临床-文章 分页查询表单 + * + * @Author xing + * @Date 2025-08-04 10:17:15 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseClinicalVideoLabelQueryListForm { + + @Schema(description = "父级ID,默认为0表示获取顶级标签") + private String pId = "0"; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoQueryForm.java new file mode 100644 index 0000000..13be4bf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoQueryForm.java @@ -0,0 +1,36 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDate; + +/** + * 病例库-临床-视频 分页查询表单 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseClinicalVideoQueryForm extends PageParam { + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "状态") + private Integer videoStatus; + + @Schema(description = "删除状态") + private Integer deleteStatus; + + @Schema(description = "发表时间") + private LocalDate pushDateBegin; + + @Schema(description = "发表时间") + private LocalDate pushDateEnd; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoStatusUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoStatusUpdateForm.java new file mode 100644 index 0000000..54b6f61 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoStatusUpdateForm.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +/** + * 病例库-临床-视频 状态更新表单 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ +@Data +@Schema(description = "病例库-临床-视频 状态更新表单") +public class CaseClinicalVideoStatusUpdateForm { + + @Schema(description = "视频ID") + @NotNull(message = "视频ID不能为空") + private Long videoId; + + @Schema(description = "状态 1:正常 2:禁用") + @NotNull(message = "状态不能为空") + private Integer status; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoUpdateForm.java new file mode 100644 index 0000000..9e5d555 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/form/CaseClinicalVideoUpdateForm.java @@ -0,0 +1,66 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import java.time.LocalDateTime; +import lombok.Data; +import net.lab1024.sa.base.common.json.deserializer.FileKeyVoDeserializer; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoAuthorForm; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.CaseClinicalVideoLabelForm; +import java.util.List; + +/** + * 病例库-临床-视频 更新表单 + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalVideoUpdateForm { + + @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "主键id 不能为空") + private Long videoId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "标题 不能为空") + private String videoTitle; + + @Schema(description = "状态(1:正常 2:禁用)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态(1:正常 2:禁用) 不能为空") + private Integer videoStatus; + + @Schema(description = "删除状态(0:否 1:是)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "删除状态(0:否 1:是) 不能为空") + private Integer deleteStatus; + + @Schema(description = "视频编号(保利)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "视频编号 不能为空") + private String videoNo; + + @Schema(description = "发表时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "发表时间 不能为空") + private LocalDateTime pushDate; + + @Schema(description = "是否外部链接(0:否 1:是)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "是否外部链接(0:否 1:是) 不能为空") + private Integer isLink; + + @Schema(description = "外部链接地址") + private String isLinkUrl; + + @Schema(description = "分享二维码地址") + @JsonDeserialize(using = FileKeyVoDeserializer.class) + private String shareQrcode; + + @Schema(description = "作者列表") + public List authorList; + + @Schema(description = "标签列表") + private List labelList; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoAuthorVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoAuthorVO.java new file mode 100644 index 0000000..6b46f60 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoAuthorVO.java @@ -0,0 +1,35 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; + +/** + * 病例库-临床-视频作者 列表VO + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalVideoAuthorVO { + @Schema(description = "主键id") + private Long authorId; + + @Schema(description = "临床文章id") + private Long articleId; + + @Schema(description = "医生id") + private Long doctorId; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + + @Schema(description = "医生数据") + private CaseClinicalDoctorVO caseClinicalDoctor; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoLabelVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoLabelVO.java new file mode 100644 index 0000000..11f65c3 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoLabelVO.java @@ -0,0 +1,34 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-临床-视频标签 列表VO + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalVideoLabelVO { + @Schema(description = "主键id") + private Long videoLabelId; + + @Schema(description = "视频id") + private Long videoId; + + @Schema(description = "app唯一标识") + private String appIden; + + @Schema(description = "标签名称") + private String labelName; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoVO.java new file mode 100644 index 0000000..071a989 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/domain/vo/CaseClinicalVideoVO.java @@ -0,0 +1,79 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo; + +import cn.hutool.core.bean.BeanUtil; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoEntity; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoAuthorVO; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoLabelVO; +import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer; + +/** + * 病例库-临床-视频 列表VO + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Data +public class CaseClinicalVideoVO { + @Schema(description = "主键id") + private Long videoId; + + @Schema(description = "标题") + private String videoTitle; + + @Schema(description = "状态(1:正常 2:禁用)") + private Integer videoStatus; + + @Schema(description = "删除状态(0:否 1:是)") + private Integer deleteStatus; + + @Schema(description = "阅读量") + private Integer readNum; + + @Schema(description = "收藏量") + private Integer collectNum; + + @Schema(description = "评论数") + private Integer commentNum; + + @Schema(description = "视频编号(保利)") + private String videoNo; + + @Schema(description = "证书图片") +// @JsonSerialize(using = FileKeyVoSerializer.class) + private String certImage; + + @Schema(description = "发表时间") + private LocalDateTime pushDate; + + @Schema(description = "是否外部链接(0:否 1:是)") + private Integer isLink; + + @Schema(description = "外部链接地址") + private String isLinkUrl; + + @Schema(description = "分享二维码地址") +// @JsonSerialize(using = FileKeyVoSerializer.class) + private String shareQrcode; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + + @Schema(description = "作者数据") + private List caseClinicalVideoAuthor; + + @Schema(description = "标签数据") + private List caseClinicalVideoLabel; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/manager/CaseClinicalVideoManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/manager/CaseClinicalVideoManager.java new file mode 100644 index 0000000..3ec1470 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/manager/CaseClinicalVideoManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.manager; + +import net.lab1024.sa.admin.module.business.caseClinicalVideo.dao.CaseClinicalVideoDao; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoEntity; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 病例库-临床-视频 Manager + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ +@Service +public class CaseClinicalVideoManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/service/CaseClinicalVideoService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/service/CaseClinicalVideoService.java new file mode 100644 index 0000000..70fb84a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseClinicalVideo/service/CaseClinicalVideoService.java @@ -0,0 +1,826 @@ +package net.lab1024.sa.admin.module.business.caseClinicalVideo.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import net.lab1024.sa.admin.extend.app.UserInfo.GetUserInfoResponse; +import net.lab1024.sa.admin.module.business.basicHospital.dao.BasicHospitalDao; +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; +import net.lab1024.sa.admin.module.business.caseClinical.service.CaseClinicalService; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.dao.CaseClinicalVideoDao; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.dao.CaseClinicalVideoLabelDao; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoEntity; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoLabelEntity; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.form.*; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoVO; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoLabelVO; +import net.lab1024.sa.admin.extend.weChat.WxMaServiceUtils; +import net.lab1024.sa.admin.extend.aliyun.Oss; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorCertDao; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorCertEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDao; +import net.lab1024.sa.admin.module.business.user.service.UserService; +import net.lab1024.sa.admin.util.ImageUtil; +import net.lab1024.sa.admin.util.Replace; +import net.lab1024.sa.base.common.exception.BusinessException; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import org.springframework.beans.factory.annotation.Value; + +import net.lab1024.sa.admin.module.business.caseClinicalVideo.dao.CaseClinicalVideoAuthorDao; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.entity.CaseClinicalVideoAuthorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalVideo.domain.vo.CaseClinicalVideoAuthorVO; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorDao; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.base.common.util.SmartResponseUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import net.lab1024.sa.admin.util.Replace; + +import jakarta.annotation.Resource; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.interceptor.TransactionAspectSupport; + +/** + * 病例库-临床-视频 Service + * + * @Author xing + * @Date 2025-08-08 13:26:37 + * @Copyright gdxz + */ + +@Service +public class CaseClinicalVideoService { + + @Resource + private CaseClinicalVideoDao caseClinicalVideoDao; + + @Resource + private CaseClinicalService caseClinicalService; + + @Resource + private StatsCaseClinicalDao statsCaseClinicalDao; + + @Resource + private CaseClinicalVideoAuthorDao caseClinicalVideoAuthorDao; + + @Resource + private CaseClinicalDoctorDao caseClinicalDoctorDao; + + @Resource + private BasicHospitalDao basicHospitalDao; + + @Resource + private WxMaServiceUtils wxMaServiceUtils; + + @Resource + private CaseClinicalVideoLabelDao caseClinicalVideoLabelDao; + + @Resource + private UserService userService; + + @Resource + private CaseClinicalDoctorCertDao caseClinicalDoctorCertDao; + + @Value("${spring.profiles.active:prod}") + private String activeProfile; + + /** + * 分页查询 + */ + public PageResult queryPage(CaseClinicalVideoQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = caseClinicalVideoDao.queryPage(page, queryForm); + for (CaseClinicalVideoVO vo : list) { + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalVideoAuthorEntity::getVideoId, vo.getVideoId()); + List caseClinicalVideoAuthors = caseClinicalVideoAuthorDao.selectList(authorQueryWrapper); + + List caseClinicalVideoAuthorVOs = SmartBeanUtil.copyList(caseClinicalVideoAuthors, CaseClinicalVideoAuthorVO.class); + + // 为每个作者VO设置医生数据 + for (CaseClinicalVideoAuthorVO authorVO : caseClinicalVideoAuthorVOs) { + // 查询医生 + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectById(authorVO.getDoctorId()); + if (caseClinicalDoctor != null) { + // 查询医生所属医院 + BasicHospitalEntity basicHospital = basicHospitalDao.selectById(caseClinicalDoctor.getHospitalId()); + if (basicHospital != null) { + caseClinicalDoctor.setBasicHospital(basicHospital); + } + + // 转换为VO并设置医院信息 + CaseClinicalDoctorVO caseClinicalDoctorVO = SmartBeanUtil.copy(caseClinicalDoctor, CaseClinicalDoctorVO.class); + if (basicHospital != null) { + caseClinicalDoctorVO.setHospitalName(basicHospital.getHospitalName()); + caseClinicalDoctorVO.setHospitalProvince(basicHospital.getProvince()); + caseClinicalDoctorVO.setHospitalCity(basicHospital.getCity()); + } + + authorVO.setCaseClinicalDoctor(caseClinicalDoctorVO); + } + + } + + vo.setCaseClinicalVideoAuthor(caseClinicalVideoAuthorVOs); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalVideoLabelEntity::getVideoId, vo.getVideoId()); + List caseClinicalVideoLabels = caseClinicalVideoLabelDao.selectList(labelQueryWrapper); + + // 转换为VO + List caseClinicalVideoLabelVOs = SmartBeanUtil.copyList(caseClinicalVideoLabels, CaseClinicalVideoLabelVO.class); + vo.setCaseClinicalVideoLabel(caseClinicalVideoLabelVOs); + } + + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 添加 + */ + @Transactional + public ResponseDTO add(CaseClinicalVideoAddForm addForm) { + // 新增视频 + CaseClinicalVideoEntity caseClinicalVideo = SmartBeanUtil.copy(addForm, CaseClinicalVideoEntity.class); + caseClinicalVideoDao.insert(caseClinicalVideo); + + // 新增统计 + IncClinicalVideoStats(String.valueOf(caseClinicalVideo.getVideoId()),4,1); + + // 生成视频分享二维码 + byte[] qrcodeBytes = addUnlimitedQrcode(caseClinicalVideo.getVideoId()); + if (qrcodeBytes == null || qrcodeBytes.length == 0) { + return ResponseDTO.userErrorParam("添加失败"); + } + + // 处理视频作者 + HandleVideoAuthor(caseClinicalVideo,addForm.getAuthorList(),qrcodeBytes); + + // 处理视频标签 + HandleVideoLabel(caseClinicalVideo,addForm.getLabelList()); + + return ResponseDTO.ok(); + } + + /** + * 更新 + */ + @Transactional + public ResponseDTO update(CaseClinicalVideoUpdateForm updateForm) { + // 获取视频数据 + CaseClinicalVideoEntity caseClinicalVideo = caseClinicalVideoDao.selectById(updateForm.getVideoId()); + if (caseClinicalVideo == null) { + throw new BusinessException("修改失败"); + } + + // 修改 + if (!Objects.equals(caseClinicalVideo.getVideoTitle(), updateForm.getVideoTitle())) { + caseClinicalVideo.setVideoTitle(updateForm.getVideoTitle()); + } + + if (!Objects.equals(caseClinicalVideo.getPushDate(), updateForm.getPushDate())) { + caseClinicalVideo.setPushDate(updateForm.getPushDate()); + } + + if (!Objects.equals(caseClinicalVideo.getIsLink(), updateForm.getIsLink())) { + caseClinicalVideo.setIsLink(updateForm.getIsLink()); + } + + if (!Objects.equals(caseClinicalVideo.getIsLinkUrl(), updateForm.getIsLinkUrl())) { + caseClinicalVideo.setIsLinkUrl(updateForm.getIsLinkUrl()); + } + + if (!Objects.equals(caseClinicalVideo.getVideoNo(), updateForm.getVideoNo())) { + caseClinicalVideo.setVideoNo(updateForm.getVideoNo()); + } + + // 如果视频状态发生改变,修正统计数据 + if (!Objects.equals(caseClinicalVideo.getVideoStatus(), updateForm.getVideoStatus())) { + caseClinicalVideo.setVideoStatus(updateForm.getVideoStatus()); + + // 修改统计数量 + DecClinicalVideoStats(String.valueOf(caseClinicalVideo.getVideoId()),4,1); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalVideoLabelEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoLabels = caseClinicalVideoLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalVideoLabelEntity label : caseClinicalVideoLabels){ + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(),2); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalVideoAuthorEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoAuthors = caseClinicalVideoAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalVideoAuthorEntity author : caseClinicalVideoAuthors){ + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId,author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 减少医生统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()),2); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),2); + } + } + + caseClinicalVideoDao.updateById(caseClinicalVideo); + + // 处理视频作者 + HandleVideoAuthor(caseClinicalVideo,updateForm.getAuthorList(),null); + + // 处理视频标签 + HandleVideoLabel(caseClinicalVideo,updateForm.getLabelList()); + + return ResponseDTO.ok(); + } + + /** + * 批量删除 + */ + @Transactional + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)){ + return ResponseDTO.ok(); + } + + for (Long videoId : idList) { + if (null == videoId){ + throw new BusinessException("删除失败"); + } + + CaseClinicalVideoEntity caseClinicalVideo = caseClinicalVideoDao.selectById(videoId); + if (caseClinicalVideo == null){ + throw new BusinessException("删除失败"); + } + + // 修改为删除 + caseClinicalVideo.setDeleteStatus(1); + caseClinicalVideoDao.updateById(caseClinicalVideo); + + // 修改统计数量 + DecClinicalVideoStats(String.valueOf(caseClinicalVideo.getVideoId()),4,1); + + // 获取视频标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalVideoLabelEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoLabels = caseClinicalVideoLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalVideoLabelEntity label : caseClinicalVideoLabels){ + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(),2); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalVideoAuthorEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoAuthors = caseClinicalVideoAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalVideoAuthorEntity author : caseClinicalVideoAuthors){ + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId,author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 减少医生统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()),2); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),2); + } + + caseClinicalVideoDao.deleteById(videoId); + } + + return ResponseDTO.ok(); + } + + /** + * 单个删除 + */ + public ResponseDTO delete(Long videoId) { + if (null == videoId){ + return ResponseDTO.ok(); + } + + CaseClinicalVideoEntity caseClinicalVideo = caseClinicalVideoDao.selectById(videoId); + if (caseClinicalVideo == null){ + return ResponseDTO.userErrorParam("删除失败"); + } + + // 修改为删除 + caseClinicalVideo.setDeleteStatus(1); + caseClinicalVideoDao.updateById(caseClinicalVideo); + + // 修改统计数量 + DecClinicalVideoStats(String.valueOf(caseClinicalVideo.getVideoId()),4,1); + + // 获取视频标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalVideoLabelEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoLabels = caseClinicalVideoLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalVideoLabelEntity label : caseClinicalVideoLabels){ + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(),2); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalVideoAuthorEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoAuthors = caseClinicalVideoAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalVideoAuthorEntity author : caseClinicalVideoAuthors){ + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId,author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 减少医生统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()),2); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),2); + } + + return ResponseDTO.ok(); + } + + /** + * 生成视频分享二维码 + */ + public byte[] addUnlimitedQrcode(Long videoId) { + try { + // 检查视频是否存在 + CaseClinicalVideoEntity video = caseClinicalVideoDao.selectById(videoId); + if (video == null) { + throw new BusinessException("视频不存在"); + } + + // 生成二维码参数 + String scene = "?id=" + videoId + "&type=2"; + String page = "pages/detail/detail"; + + // 生成二维码 + byte[] qrcodeBytes = wxMaServiceUtils.getUnlimitedQrcode(scene, page); + + // 生成文件名 + String fileName; + String no = "v" + videoId; + + // 根据环境设置路径 + String envPath = Objects.equals(activeProfile, "dev") ? "dev/" : "prod/"; + fileName = envPath + "static/images/" + no + ".png"; + + // 上传到OSS + boolean res = Oss.putObject(fileName, qrcodeBytes); + if (!res) { + throw new BusinessException("上传二维码失败"); + } + + // 更新视频记录 + video.setShareQrcode("/" + fileName); + caseClinicalVideoDao.updateById(video); + + return qrcodeBytes; + } catch (Exception e) { + throw new BusinessException(e.getMessage()); + } + } + + /** + * 获取视频详情 + */ + public ResponseDTO getDetail(Long videoId) { + CaseClinicalVideoEntity entity = caseClinicalVideoDao.selectById(videoId); + if (entity == null) { + return ResponseDTO.userErrorParam("视频不存在"); + } + + CaseClinicalVideoVO vo = SmartBeanUtil.copy(entity, CaseClinicalVideoVO.class); + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalVideoAuthorEntity::getVideoId, videoId); + List caseClinicalVideoAuthors = caseClinicalVideoAuthorDao.selectList(authorQueryWrapper); + + List caseClinicalVideoAuthorVOs = SmartBeanUtil.copyList(caseClinicalVideoAuthors, CaseClinicalVideoAuthorVO.class); + + // 为每个作者VO设置医生数据 + for (CaseClinicalVideoAuthorVO authorVO : caseClinicalVideoAuthorVOs) { + // 查询医生 + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectById(authorVO.getDoctorId()); + if (caseClinicalDoctor != null) { + // 查询医生所属医院 + BasicHospitalEntity basicHospital = basicHospitalDao.selectById(caseClinicalDoctor.getHospitalId()); + if (basicHospital != null) { + caseClinicalDoctor.setBasicHospital(basicHospital); + } + + // 转换为VO并设置医院信息 + CaseClinicalDoctorVO caseClinicalDoctorVO = SmartBeanUtil.copy(caseClinicalDoctor, CaseClinicalDoctorVO.class); + if (basicHospital != null) { + caseClinicalDoctorVO.setHospitalName(basicHospital.getHospitalName()); + caseClinicalDoctorVO.setHospitalProvince(basicHospital.getProvince()); + caseClinicalDoctorVO.setHospitalCity(basicHospital.getCity()); + } + + authorVO.setCaseClinicalDoctor(caseClinicalDoctorVO); + } + } + + vo.setCaseClinicalVideoAuthor(caseClinicalVideoAuthorVOs); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalVideoLabelEntity::getVideoId, videoId); + List caseClinicalVideoLabels = caseClinicalVideoLabelDao.selectList(labelQueryWrapper); + + // 转换为VO + List caseClinicalVideoLabelVOs = SmartBeanUtil.copyList(caseClinicalVideoLabels, CaseClinicalVideoLabelVO.class); + vo.setCaseClinicalVideoLabel(caseClinicalVideoLabelVOs); + + vo.setShareQrcode(Replace.addOssDomain(vo.getShareQrcode())); + return ResponseDTO.ok(vo); + } + + /** + * 更新状态 + */ + public ResponseDTO updateStatus(Long videoId, Integer status) { + if (null == videoId) { + return ResponseDTO.userErrorParam("视频ID不能为空"); + } + + CaseClinicalVideoEntity caseClinicalVideo = caseClinicalVideoDao.selectById(videoId); + if (caseClinicalVideo == null) { + return ResponseDTO.userErrorParam("视频不存在"); + } + + // 如果状态没有变化,直接返回 + if (Objects.equals(caseClinicalVideo.getVideoStatus(), status)) { + return ResponseDTO.ok(); + } + + // 更新状态 + caseClinicalVideo.setVideoStatus(status); + caseClinicalVideoDao.updateById(caseClinicalVideo); + + // 如果状态发生改变,修正统计数据 + if (status == 2) { + // 状态改为禁用,减少统计数量 + DecClinicalVideoStats(String.valueOf(caseClinicalVideo.getVideoId()), 4, 1); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalVideoLabelEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoLabels = caseClinicalVideoLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalVideoLabelEntity label : caseClinicalVideoLabels) { + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(), 2); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalVideoAuthorEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoAuthors = caseClinicalVideoAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalVideoAuthorEntity author : caseClinicalVideoAuthors) { + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId, author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 减少医生统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()), 2); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()), 2); + } + } else if (status == 1) { + // 状态改为正常,增加统计数量 + IncClinicalVideoStats(String.valueOf(caseClinicalVideo.getVideoId()), 4, 1); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalVideoLabelEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoLabels = caseClinicalVideoLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalVideoLabelEntity label : caseClinicalVideoLabels) { + // 增加标签统计 + LocalDateTime lastPushDate = caseClinicalVideoDao.selectLastVideoPushDateByLabelId(label.getAppIden()); + caseClinicalService.IncStatsCaseClinicalLabel(label.getAppIden(), label.getLabelName(), 2, lastPushDate); + } + + // 获取作者数据 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalVideoAuthorEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoAuthors = caseClinicalVideoAuthorDao.selectList(authorQueryWrapper); + for (CaseClinicalVideoAuthorEntity author : caseClinicalVideoAuthors) { + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId, author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("无法完成此操作"); + } + + // 增加医生统计 + LocalDateTime lastPushDate = caseClinicalVideoDao.selectLastVideoPushDateByDoctorId(caseClinicalDoctor.getDoctorId()); + caseClinicalService.IncStatsCaseClinicalDoctor(String.valueOf(author.getDoctorId()), 2, lastPushDate); + + // 增加医院统计 + caseClinicalService.IncStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()), 2, lastPushDate); + } + } + + return ResponseDTO.ok(); + } + + /** + * 处理视频作者 + */ + public void HandleVideoAuthor(CaseClinicalVideoEntity caseClinicalVideo, List authorList, byte[] qrCodeBytes) { + // 需新增的 + List addList = new ArrayList<>(); + + // 需删除的 + List deleteList = new ArrayList<>(); + + // 获取全部作者 + LambdaQueryWrapper authorQueryWrapper = new LambdaQueryWrapper<>(); + authorQueryWrapper.eq(CaseClinicalVideoAuthorEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoAuthors = caseClinicalVideoAuthorDao.selectList(authorQueryWrapper); + + // 处理新增的情况 + for (CaseClinicalVideoAuthorForm a : authorList){ + // 默认本条为新增 + boolean exists = true; + for (CaseClinicalVideoAuthorEntity b : caseClinicalVideoAuthors){ + if (Objects.equals(a.getDoctorId(), b.getDoctorId())){ + exists = false; + break; // 已存在,跳出内层循环 + } + } + + if (exists) { + addList.add(a); // 不存在于旧数据中,加入新增列表 + } + } + + // 处理删除的情况 + for (CaseClinicalVideoAuthorEntity b : caseClinicalVideoAuthors){ + // 默认本条为删除 + boolean exists = true; + for (CaseClinicalVideoAuthorForm a : authorList){ + if (Objects.equals(a.getDoctorId(), b.getDoctorId())){ + exists = false; + break; // 已存在,跳出内层循环 + } + } + + if (exists) { + deleteList.add(b); // 加入删除列表 + } + } + + // 删除 + for (CaseClinicalVideoAuthorEntity author : deleteList){ + // 获取医生数据 + LambdaQueryWrapper doctorQueryWrapper = new LambdaQueryWrapper<>(); + doctorQueryWrapper.eq(CaseClinicalDoctorEntity::getDoctorId, author.getDoctorId()); + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectOne(doctorQueryWrapper); + if (caseClinicalDoctor == null) { + throw new BusinessException("操作失败"); + } + + // 获取医院数据 + BasicHospitalEntity basicHospital = basicHospitalDao.selectById(caseClinicalDoctor.getHospitalId()); + if (basicHospital == null) { + throw new BusinessException("操作失败"); + } + + // 减少作者统计 + caseClinicalService.DecStatsCaseClinicalDoctor(String.valueOf(caseClinicalDoctor.getDoctorId()),2); + + // 减少医院统计 + caseClinicalService.DecStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),2); + + // 删除该作者 + caseClinicalVideoAuthorDao.deleteById(author.getAuthorId()); + + // 删除该作者证书 + LambdaQueryWrapper certWrapper = new LambdaQueryWrapper<>(); + certWrapper.eq(CaseClinicalDoctorCertEntity::getDoctorId, caseClinicalDoctor.getDoctorId()); + certWrapper.eq(CaseClinicalDoctorCertEntity::getId, caseClinicalVideo.getVideoId()); + certWrapper.eq(CaseClinicalDoctorCertEntity::getType, 2); + caseClinicalDoctorCertDao.delete(certWrapper); + } + + // 新增新的作者 + for (CaseClinicalVideoAuthorForm author : addList){ + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectById(author.getDoctorId()); + + CaseClinicalVideoAuthorEntity caseClinicalVideoAuthor = new CaseClinicalVideoAuthorEntity(); + caseClinicalVideoAuthor.setVideoId(caseClinicalVideo.getVideoId()); + caseClinicalVideoAuthor.setDoctorId(caseClinicalDoctor.getDoctorId()); + caseClinicalVideoAuthorDao.insert(caseClinicalVideoAuthor); + + LocalDateTime lastPushDate = caseClinicalVideoDao.selectLastVideoPushDateByDoctorId(caseClinicalDoctor.getDoctorId()); + + // 新增作者统计 + caseClinicalService.IncStatsCaseClinicalDoctor(String.valueOf(caseClinicalDoctor.getDoctorId()),2,lastPushDate); + + // 新增医院统计 + caseClinicalService.IncStatsCaseClinicalHospital(String.valueOf(caseClinicalDoctor.getHospitalId()),2,lastPushDate); + + // 生成用户证书-文章/视频 + if (qrCodeBytes == null || qrCodeBytes.length == 0) { + // 生成二维码图片 + if (caseClinicalVideo.getShareQrcode() == null){ + try { + // 生成用户分享二维码-文章/视频 + qrCodeBytes = addUnlimitedQrcode(caseClinicalVideo.getVideoId()); + } catch (Exception e) { + // 不处理 + throw new BusinessException("操作失败"); + } + }else{ + // 下载二维码图片 + qrCodeBytes = Oss.getObjectToByte(caseClinicalVideo.getShareQrcode().replaceFirst("^/+", "")); + if (qrCodeBytes == null) { + throw new BusinessException("操作失败"); + } + } + } + + // 下载头像 + byte[] avatarByte = new byte[0]; + if (caseClinicalDoctor.getAvatar() != null && !caseClinicalDoctor.getAvatar().isEmpty()) { + avatarByte = Oss.getObjectToByte(caseClinicalDoctor.getAvatar().replaceFirst("^/+", "")); + }else{ + try { + avatarByte = ImageUtil.readImageToBytes("static/cert/avatar.png"); + } catch (Exception e) { + throw new BusinessException(e.getMessage()); + } + } + + if (avatarByte == null) { + throw new BusinessException("操作失败"); + } + + userService.CreateUserCert( + String.valueOf(caseClinicalVideo.getVideoId()), + 2, + String.valueOf(caseClinicalDoctor.getDoctorId()), + qrCodeBytes, + avatarByte + ); + } + } + + /** + * 处理视频标签 + */ + public void HandleVideoLabel(CaseClinicalVideoEntity caseClinicalVideo, List labelList) { + // 获取全部标签 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseClinicalVideoLabelEntity::getVideoId, caseClinicalVideo.getVideoId()); + List caseClinicalVideoLabels = caseClinicalVideoLabelDao.selectList(labelQueryWrapper); + for (CaseClinicalVideoLabelEntity label : caseClinicalVideoLabels){ + // 减少标签统计 + caseClinicalService.DecStatsCaseClinicalLabel(label.getAppIden(),2); + + // 删除视频标签 + caseClinicalVideoLabelDao.deleteById(label.getVideoLabelId()); + } + + for (CaseClinicalVideoLabelForm label : labelList){ + CaseClinicalVideoLabelEntity caseClinicalVideoLabel = new CaseClinicalVideoLabelEntity(); + caseClinicalVideoLabel.setVideoId(caseClinicalVideo.getVideoId()); + caseClinicalVideoLabel.setAppIden(label.getAppIden()); + caseClinicalVideoLabel.setLabelName(label.getLabelName()); + caseClinicalVideoLabelDao.insert(caseClinicalVideoLabel); + + LocalDateTime lastPushDate = caseClinicalVideoDao.selectLastVideoPushDateByLabelId(label.getAppIden()); + + // 新增标签统计 + caseClinicalService.IncStatsCaseClinicalLabel(label.getAppIden(),caseClinicalVideoLabel.getLabelName(),2,lastPushDate); + } + } + + /** + * 新增视频的统计字段 + * @param videoId 视频id + * @param type 类型:1:阅读量 2:收藏量 3:评论数 4:文章数 + */ + @Transactional + public boolean IncClinicalVideoStats(String videoId,Integer type,Integer num){ + try { + String caseClinicalVideoField = ""; // 具体文章 + String statsCaseClinicalField = ""; // 全部文章 + + // 阅读 + if (type == 1){ + caseClinicalVideoField = "read_num"; // 具体文章 + statsCaseClinicalField = "video_read_num"; // 全部文章 + } + + // 收藏 + if (type == 2){ + caseClinicalVideoField = "collect_num"; // 具体文章 + statsCaseClinicalField = "video_collect_num"; // 全部文章 + } + + // 评论 + if (type == 3){ + caseClinicalVideoField = "comment_num"; // 具体文章 + statsCaseClinicalField = "video_comment_num"; // 全部文章 + } + + // 文章数 + if (type == 4){ + statsCaseClinicalField = "video_num"; // 全部文章 + } + + if (!caseClinicalVideoField.isEmpty()){ + caseClinicalVideoDao.inc(Long.valueOf(videoId),caseClinicalVideoField,num); + } + + statsCaseClinicalDao.inc(1L,statsCaseClinicalField,num); + + return true; + } catch (Exception e) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return false; + } + } + + /** + * 减少视频的统计字段 + * @param videoId 文章id + * @param type 类型:1:阅读量 2:收藏量 3:评论数 4:文章数 + */ + @Transactional + public boolean DecClinicalVideoStats(String videoId,Integer type,Integer num){ + try { + String caseClinicalVideoField = ""; // 具体文章 + String statsCaseClinicalField = ""; // 全部文章 + + // 阅读 + if (type == 1){ + caseClinicalVideoField = "read_num"; // 具体文章 + statsCaseClinicalField = "video_read_num"; // 全部文章 + } + + // 收藏 + if (type == 2){ + caseClinicalVideoField = "collect_num"; // 具体文章 + statsCaseClinicalField = "video_collect_num"; // 全部文章 + } + + // 评论 + if (type == 3){ + caseClinicalVideoField = "comment_num"; // 具体文章 + statsCaseClinicalField = "video_comment_num"; // 全部文章 + } + + // 文章数 + if (type == 4){ + statsCaseClinicalField = "video_num"; // 全部文章 + } + + if (!caseClinicalVideoField.isEmpty()){ + caseClinicalVideoDao.dec(Long.valueOf(videoId),caseClinicalVideoField,num); + } + + statsCaseClinicalDao.dec(1L,statsCaseClinicalField,num); + + return true; + } catch (Exception e) { + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + return false; + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeController.java new file mode 100644 index 0000000..4765390 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeController.java @@ -0,0 +1,114 @@ +package net.lab1024.sa.admin.module.business.caseExchange.controller; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeAddForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeUpdateForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeStatusUpdateForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeSelectedUpdateForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeVoteUpdateForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVO; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteDetailVO; +import net.lab1024.sa.admin.module.business.caseExchange.service.CaseExchangeService; +import net.lab1024.sa.admin.module.business.caseExchange.service.CaseExchangeVoteService; +import net.lab1024.sa.base.common.domain.ValidateList; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 病例库-病例交流 Controller + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "病例库-病例交流") +public class CaseExchangeController { + + @Resource + private CaseExchangeService caseExchangeService; + + @Resource + private CaseExchangeVoteService caseExchangeVoteService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/caseExchange/queryPage") + @SaCheckPermission("caseExchange:query") + public ResponseDTO> queryPage(@RequestBody @Valid CaseExchangeQueryForm queryForm) { + return ResponseDTO.ok(caseExchangeService.queryPage(queryForm)); + } + + @Operation(summary = "添加 @author xing") + @PostMapping("/caseExchange/add") + @SaCheckPermission("caseExchange:add") + public ResponseDTO add(@RequestBody @Valid CaseExchangeAddForm addForm) { + return caseExchangeService.add(addForm); + } + + @Operation(summary = "更新 @author xing") + @PostMapping("/caseExchange/update") + @SaCheckPermission("caseExchange:update") + public ResponseDTO update(@RequestBody @Valid CaseExchangeUpdateForm updateForm) { + return caseExchangeService.update(updateForm); + } + + @Operation(summary = "批量删除 @author xing") + @PostMapping("/caseExchange/batchDelete") + @SaCheckPermission("caseExchange:delete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return caseExchangeService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author xing") + @GetMapping("/caseExchange/delete/{exchangeId}") + @SaCheckPermission("caseExchange:delete") + public ResponseDTO batchDelete(@PathVariable Long exchangeId) { + return caseExchangeService.delete(exchangeId); + } + + @Operation(summary = "获取详情 @author xing") + @GetMapping("/caseExchange/getDetail/{exchangeId}") + @SaCheckPermission("caseExchange:query") + public ResponseDTO getDetail(@PathVariable Long exchangeId) { + return caseExchangeService.getDetail(exchangeId); + } + + @Operation(summary = "获取投票信息 @author xing") + @GetMapping("/caseExchange/getVoteInfo/{exchangeId}") + @SaCheckPermission("caseExchange:query") + public ResponseDTO getVoteInfo(@PathVariable Long exchangeId) { + return caseExchangeVoteService.getVoteDetailByExchangeId(exchangeId); + } + + @Operation(summary = "更新投票信息 @author xing") + @PostMapping("/caseExchange/vote/update") + @SaCheckPermission("caseExchange:update") + public ResponseDTO updateVote(@RequestBody @Valid CaseExchangeVoteUpdateForm updateForm) { + return caseExchangeVoteService.updateVote(updateForm); + } + + @Operation(summary = "修改状态 @author xing") + @PostMapping("/caseExchange/status/update") + @SaCheckPermission("caseExchange:update") + public ResponseDTO statusUpdate(@RequestBody @Valid CaseExchangeStatusUpdateForm updateForm) { + return caseExchangeService.updateStatus(updateForm.getExchangeId(), updateForm.getStatus()); + } + + @Operation(summary = "修改精选状态 @author xing") + @PostMapping("/caseExchange/selected/update") + @SaCheckPermission("caseExchange:update") + public ResponseDTO selectedUpdate(@RequestBody @Valid CaseExchangeSelectedUpdateForm updateForm) { + return caseExchangeService.updateSelected(updateForm.getExchangeId(), updateForm.getIsSelected()); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeLabelController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeLabelController.java new file mode 100644 index 0000000..96e7bd6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeLabelController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseExchange.controller; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeLabelQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeLabelVO; +import net.lab1024.sa.admin.module.business.caseExchange.service.CaseExchangeLabelService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 病例库-病例交流-标签 Controller + * + * @Author xing + * @Date 2025-08-10 22:34:44 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "病例库-病例交流-标签") +public class CaseExchangeLabelController { + + @Resource + private CaseExchangeLabelService caseExchangeLabelService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/caseExchangeLabel/queryPage") + @SaCheckPermission("caseExchangeLabel:query") + public ResponseDTO> queryPage(@RequestBody @Valid CaseExchangeLabelQueryForm queryForm) { + return ResponseDTO.ok(caseExchangeLabelService.queryPage(queryForm)); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeVoteController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeVoteController.java new file mode 100644 index 0000000..d12fc81 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeVoteController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseExchange.controller; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeVoteQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteVO; +import net.lab1024.sa.admin.module.business.caseExchange.service.CaseExchangeVoteService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 病例库-病例交流-投票 Controller + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "病例库-病例交流-投票") +public class CaseExchangeVoteController { + + @Resource + private CaseExchangeVoteService caseExchangeVoteService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/caseExchangeVote/queryPage") + @SaCheckPermission("caseExchangeVote:query") + public ResponseDTO> queryPage(@RequestBody @Valid CaseExchangeVoteQueryForm queryForm) { + return ResponseDTO.ok(caseExchangeVoteService.queryPage(queryForm)); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeVoteOptionController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeVoteOptionController.java new file mode 100644 index 0000000..88e02ed --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/CaseExchangeVoteOptionController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseExchange.controller; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeVoteOptionQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteOptionVO; +import net.lab1024.sa.admin.module.business.caseExchange.service.CaseExchangeVoteOptionService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 病例交流-投票详情 Controller + * + * @Author xing + * @Date 2025-08-10 23:02:14 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "病例交流-投票详情") +public class CaseExchangeVoteOptionController { + + @Resource + private CaseExchangeVoteOptionService caseExchangeVoteOptionService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/caseExchangeVoteOption/queryPage") + @SaCheckPermission("caseExchangeVoteOption:query") + public ResponseDTO> queryPage(@RequestBody @Valid CaseExchangeVoteOptionQueryForm queryForm) { + return ResponseDTO.ok(caseExchangeVoteOptionService.queryPage(queryForm)); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/StatsCaseExchangeController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/StatsCaseExchangeController.java new file mode 100644 index 0000000..2a81e30 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/StatsCaseExchangeController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseExchange.controller; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.StatsCaseExchangeQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.StatsCaseExchangeVO; +import net.lab1024.sa.admin.module.business.caseExchange.service.StatsCaseExchangeService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 统计表-病例库-病例交流 Controller + * + * @Author xing + * @Date 2025-08-10 23:39:27 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "统计表-病例库-病例交流") +public class StatsCaseExchangeController { + + @Resource + private StatsCaseExchangeService statsCaseExchangeService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/statsCaseExchange/queryPage") + @SaCheckPermission("statsCaseExchange:query") + public ResponseDTO> queryPage(@RequestBody @Valid StatsCaseExchangeQueryForm queryForm) { + return ResponseDTO.ok(statsCaseExchangeService.queryPage(queryForm)); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/StatsCaseExchangeUserController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/StatsCaseExchangeUserController.java new file mode 100644 index 0000000..e89bdb5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/controller/StatsCaseExchangeUserController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseExchange.controller; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.StatsCaseExchangeUserQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.StatsCaseExchangeUserVO; +import net.lab1024.sa.admin.module.business.caseExchange.service.StatsCaseExchangeUserService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 统计表-病例库-病例交流-用户 Controller + * + * @Author xing + * @Date 2025-08-10 23:39:56 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "统计表-病例库-病例交流-用户") +public class StatsCaseExchangeUserController { + + @Resource + private StatsCaseExchangeUserService statsCaseExchangeUserService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/statsCaseExchangeUser/queryPage") + @SaCheckPermission("statsCaseExchangeUser:query") + public ResponseDTO> queryPage(@RequestBody @Valid StatsCaseExchangeUserQueryForm queryForm) { + return ResponseDTO.ok(statsCaseExchangeUserService.queryPage(queryForm)); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeDao.java new file mode 100644 index 0000000..80d5585 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeDao.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.caseExchange.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 病例库-病例交流 Dao + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@Mapper +public interface CaseExchangeDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") CaseExchangeQueryForm queryForm); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeLabelDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeLabelDao.java new file mode 100644 index 0000000..eaf9fb8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeLabelDao.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.caseExchange.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeLabelEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeLabelQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeLabelVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 病例库-病例交流-标签 Dao + * + * @Author xing + * @Date 2025-08-10 22:34:44 + * @Copyright gdxz + */ + +@Mapper +public interface CaseExchangeLabelDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") CaseExchangeLabelQueryForm queryForm); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeVoteDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeVoteDao.java new file mode 100644 index 0000000..091b2e5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeVoteDao.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.caseExchange.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeVoteEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeVoteQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteVO; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteDetailVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 病例库-病例交流-投票 Dao + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ + +@Mapper +public interface CaseExchangeVoteDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") CaseExchangeVoteQueryForm queryForm); + + /** + * 根据病例交流ID获取投票详情 + * + * @param exchangeId + * @return + */ + CaseExchangeVoteDetailVO getVoteDetailByExchangeId(@Param("exchangeId") Long exchangeId); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeVoteOptionDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeVoteOptionDao.java new file mode 100644 index 0000000..faa3717 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/CaseExchangeVoteOptionDao.java @@ -0,0 +1,49 @@ +package net.lab1024.sa.admin.module.business.caseExchange.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeVoteOptionEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeVoteOptionQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteOptionVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 病例交流-投票详情 Dao + * + * @Author xing + * @Date 2025-08-10 23:02:14 + * @Copyright gdxz + */ + +@Mapper +public interface CaseExchangeVoteOptionDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") CaseExchangeVoteOptionQueryForm queryForm); + + /** + * 根据投票ID查询选项列表 + * + * @param voteId + * @return + */ + List getOptionsByVoteId(@Param("voteId") Long voteId); + + /** + * 根据投票ID删除选项 + * + * @param voteId + * @return + */ + int deleteByVoteId(@Param("voteId") Long voteId); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/StatsCaseExchangeDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/StatsCaseExchangeDao.java new file mode 100644 index 0000000..687f079 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/StatsCaseExchangeDao.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.caseExchange.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.StatsCaseExchangeEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.StatsCaseExchangeQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.StatsCaseExchangeVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 统计表-病例库-病例交流 Dao + * + * @Author xing + * @Date 2025-08-10 23:39:27 + * @Copyright gdxz + */ + +@Mapper +public interface StatsCaseExchangeDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") StatsCaseExchangeQueryForm queryForm); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/StatsCaseExchangeUserDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/StatsCaseExchangeUserDao.java new file mode 100644 index 0000000..3eb574c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/dao/StatsCaseExchangeUserDao.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.caseExchange.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.StatsCaseExchangeUserEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.StatsCaseExchangeUserQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.StatsCaseExchangeUserVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 统计表-病例库-病例交流-用户 Dao + * + * @Author xing + * @Date 2025-08-10 23:39:56 + * @Copyright gdxz + */ + +@Mapper +public interface StatsCaseExchangeUserDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") StatsCaseExchangeUserQueryForm queryForm); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeEntity.java new file mode 100644 index 0000000..274be15 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeEntity.java @@ -0,0 +1,106 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-病例交流 实体类 + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@Data +@TableName("case_exchange") +public class CaseExchangeEntity { + + /** + * 主键id + */ + @TableId + private Long exchangeId; + + /** + * 用户id + */ + private Long userId; + + /** + * 标题 + */ + private String exchangeTitle; + + /** + * 状态(1:正常 2:禁用) + */ + private Integer exchangeStatus; + + /** + * 删除状态(0:否 1:是) + */ + private Integer deleteStatus; + + /** + * 是否被精选(0:否 1:是) + */ + private Integer isSelected; + + /** + * 阅读量 + */ + private Integer readNum; + + /** + * 收藏量 + */ + private Integer collectNum; + + /** + * 评论数 + */ + private Integer commentNum; + + /** + * 发表时间 + */ + private LocalDateTime pushDate; + + /** + * 最后一条评论时间 + */ + private LocalDateTime lastCommentTime; + + /** + * 内容 + */ + private String exchangeContent; + + /** + * 总结 + */ + private String exchangeSummary; + + /** + * 预览图片(逗号分隔) + */ + private String exchangeContentImage; + + /** + * 预览视频(逗号分隔) + */ + private String exchangeContentVideo; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeLabelEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeLabelEntity.java new file mode 100644 index 0000000..17704b8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeLabelEntity.java @@ -0,0 +1,51 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-病例交流-标签 实体类 + * + * @Author xing + * @Date 2025-08-10 22:34:44 + * @Copyright gdxz + */ + +@Data +@TableName("case_exchange_label") +public class CaseExchangeLabelEntity { + + /** + * 主键id + */ + @TableId + private Long exchangeLabelId; + + /** + * 临床文章id + */ + private Long exchangeId; + + /** + * app唯一标识 + */ + private String appIden; + + /** + * 标签名称 + */ + private String labelName; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeVoteEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeVoteEntity.java new file mode 100644 index 0000000..78076c0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeVoteEntity.java @@ -0,0 +1,51 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-病例交流-投票 实体类 + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ + +@Data +@TableName("case_exchange_vote") +public class CaseExchangeVoteEntity { + + /** + * 主键id + */ + @TableId + private Long voteId; + + /** + * 病例交流id + */ + private Long exchangeId; + + /** + * 选项标题 + */ + private String voteTitle; + + /** + * 结束投票时间 + */ + private LocalDateTime endTime; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeVoteOptionEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeVoteOptionEntity.java new file mode 100644 index 0000000..197fbf7 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/CaseExchangeVoteOptionEntity.java @@ -0,0 +1,51 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例交流-投票详情 实体类 + * + * @Author xing + * @Date 2025-08-10 23:02:14 + * @Copyright gdxz + */ + +@Data +@TableName("case_exchange_vote_option") +public class CaseExchangeVoteOptionEntity { + + /** + * 主键id + */ + @TableId + private Long optionId; + + /** + * 投票id + */ + private Long voteId; + + /** + * 选项 + */ + private String optionValue; + + /** + * 票数 + */ + private Integer voteNum; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/StatsCaseExchangeEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/StatsCaseExchangeEntity.java new file mode 100644 index 0000000..32c39bd --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/StatsCaseExchangeEntity.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-病例交流 实体类 + * + * @Author xing + * @Date 2025-08-10 23:39:27 + * @Copyright gdxz + */ + +@Data +@TableName("stats_case_exchange") +public class StatsCaseExchangeEntity { + + /** + * 主键id + */ + @TableId + private Long statsId; + + /** + * 数量-病例交流 + */ + private Integer exchangeNum; + + /** + * 总阅读量-病例交流 + */ + private Integer exchangeReadNum; + + /** + * 总收藏量-病例交流 + */ + private Integer exchangeCollectNum; + + /** + * 总评论量-病例交流 + */ + private Integer exchangeCommentNum; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/StatsCaseExchangeUserEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/StatsCaseExchangeUserEntity.java new file mode 100644 index 0000000..d75fe9d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/entity/StatsCaseExchangeUserEntity.java @@ -0,0 +1,61 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-病例交流-用户 实体类 + * + * @Author xing + * @Date 2025-08-10 23:39:56 + * @Copyright gdxz + */ + +@Data +@TableName("stats_case_exchange_user") +public class StatsCaseExchangeUserEntity { + + /** + * 主键id + */ + @TableId + private Long statsId; + + /** + * 用户id + */ + private Long userId; + + /** + * 数量-病例交流 + */ + private Integer exchangeNum; + + /** + * 总阅读量-病例交流 + */ + private Integer exchangeReadNum; + + /** + * 总收藏量-病例交流 + */ + private Integer exchangeCollectNum; + + /** + * 总评论量-病例交流 + */ + private Integer exchangeCommentNum; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeAddForm.java new file mode 100644 index 0000000..aaca6e9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeAddForm.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import java.util.List; + +/** + * 病例库-病例交流 新建表单 + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeAddForm { + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "标题 不能为空") + private String exchangeTitle; + + @Schema(description = "状态(1:正常 2:禁用)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态(1:正常 2:禁用) 不能为空") + private Integer exchangeStatus; + + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "内容 不能为空") + private String exchangeContent; + + @Schema(description = "总结", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "总结 不能为空") + private String exchangeSummary; + + @Schema(description = "标签列表") + private List labelList; + + @Data + public static class CaseExchangeLabelForm { + @Schema(description = "app唯一标识") + private String appIden; + + @Schema(description = "标签名称") + private String labelName; + } +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeLabelQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeLabelQueryForm.java new file mode 100644 index 0000000..46c009e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeLabelQueryForm.java @@ -0,0 +1,23 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 病例库-病例交流-标签 分页查询表单 + * + * @Author xing + * @Date 2025-08-10 22:34:44 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseExchangeLabelQueryForm extends PageParam { + + @Schema(description = "标签名称") + private String keywords; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeQueryForm.java new file mode 100644 index 0000000..390e1ac --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeQueryForm.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 病例库-病例交流 分页查询表单 + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseExchangeQueryForm extends PageParam { + + @Schema(description = "标题") + private String keyword; + + @Schema(description = "状态(1:正常 2:禁用)") + private Integer exchangeStatus; + + @Schema(description = "是否被精选(0:否 1:是)") + private Integer isSelected; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeSelectedUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeSelectedUpdateForm.java new file mode 100644 index 0000000..7a910f7 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeSelectedUpdateForm.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +/** + * 病例库-病例交流 精选状态更新表单 + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ +@Data +@Schema(description = "病例库-病例交流 精选状态更新表单") +public class CaseExchangeSelectedUpdateForm { + + @Schema(description = "病例交流ID") + @NotNull(message = "病例交流ID不能为空") + private Long exchangeId; + + @Schema(description = "精选状态 0:否 1:是") + @NotNull(message = "精选状态不能为空") + private Integer isSelected; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeStatusUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeStatusUpdateForm.java new file mode 100644 index 0000000..991bc32 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeStatusUpdateForm.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import jakarta.validation.constraints.NotNull; + +/** + * 病例库-病例交流 状态更新表单 + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ +@Data +@Schema(description = "病例库-病例交流 状态更新表单") +public class CaseExchangeStatusUpdateForm { + + @Schema(description = "病例交流ID") + @NotNull(message = "病例交流ID不能为空") + private Long exchangeId; + + @Schema(description = "状态 1:正常 2:禁用") + @NotNull(message = "状态不能为空") + private Integer status; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeUpdateForm.java new file mode 100644 index 0000000..7931000 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeUpdateForm.java @@ -0,0 +1,92 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 病例库-病例交流 更新表单 + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeUpdateForm { + + @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "主键id 不能为空") + private Long exchangeId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "标题 不能为空") + private String exchangeTitle; + + @Schema(description = "状态(1:正常 2:禁用)", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "状态(1:正常 2:禁用) 不能为空") + private Integer exchangeStatus; + + @Schema(description = "发表时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "发表时间 不能为空") + private LocalDateTime pushDate; + + @Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "内容 不能为空") + private String exchangeContent; + + @Schema(description = "总结", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "总结 不能为空") + private String exchangeSummary; + + @Schema(description = "标签列表") + private List labelList; + + @Data + public static class CaseExchangeLabelForm { + @Schema(description = "app唯一标识") + private String appIden; + + @Schema(description = "标签名称") + private String labelName; + } + + + + /** + * 投票 + */ + @JsonIgnoreProperties(ignoreUnknown = true) + @Data + public static class CaseExchangeVoteRequest { + @JsonProperty("vote_title") + @NotEmpty(message = "请输入投票标题") + private String voteTitle; // 选项标题 + + @JsonProperty("valid_day") + @Size(min = 1, max = 20, message = "有效期在1-20天内") + private Integer validDay; // 投票有效期天数 + + @JsonProperty("case_exchange_vote_option") + private List caseExchangeVoteOption; + } + + /** + * 投票选项 + */ + @JsonIgnoreProperties(ignoreUnknown = true) + @Data + public static class CaseExchangeVoteOptionRequest { + @JsonProperty("option_value") + private String optionValue; // 选项 + } + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteOptionQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteOptionQueryForm.java new file mode 100644 index 0000000..8448640 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteOptionQueryForm.java @@ -0,0 +1,19 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 病例交流-投票详情 分页查询表单 + * + * @Author xing + * @Date 2025-08-10 23:02:14 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseExchangeVoteOptionQueryForm extends PageParam { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteQueryForm.java new file mode 100644 index 0000000..57ddc67 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteQueryForm.java @@ -0,0 +1,19 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 病例库-病例交流-投票 分页查询表单 + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class CaseExchangeVoteQueryForm extends PageParam { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteUpdateForm.java new file mode 100644 index 0000000..023f2ed --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/CaseExchangeVoteUpdateForm.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 病例交流-投票更新 表单 + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeVoteUpdateForm { + + @Schema(description = "投票id") + private Long voteId; + + @Schema(description = "病例交流id") + @NotNull(message = "病例交流ID不能为空") + private Long exchangeId; + + @Schema(description = "选项标题") + private String voteTitle; + + @Schema(description = "结束投票时间") + private LocalDateTime endTime; + + @Schema(description = "投票选项列表") + private List optionList; + + @Data + public static class VoteOptionForm { + @Schema(description = "选项ID") + private Long optionId; + + @Schema(description = "选项值") + private String optionValue; + + @Schema(description = "票数") + private Integer voteNum; + } +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/StatsCaseExchangeQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/StatsCaseExchangeQueryForm.java new file mode 100644 index 0000000..be58866 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/StatsCaseExchangeQueryForm.java @@ -0,0 +1,19 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 统计表-病例库-病例交流 分页查询表单 + * + * @Author xing + * @Date 2025-08-10 23:39:27 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class StatsCaseExchangeQueryForm extends PageParam { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/StatsCaseExchangeUserQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/StatsCaseExchangeUserQueryForm.java new file mode 100644 index 0000000..4bcc13f --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/form/StatsCaseExchangeUserQueryForm.java @@ -0,0 +1,19 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 统计表-病例库-病例交流-用户 分页查询表单 + * + * @Author xing + * @Date 2025-08-10 23:39:56 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class StatsCaseExchangeUserQueryForm extends PageParam { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeDetailVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeDetailVO.java new file mode 100644 index 0000000..38dbaca --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeDetailVO.java @@ -0,0 +1,72 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import java.util.List; +import lombok.Data; + +/** + * 病例库-病例交流 详情VO + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeDetailVO { + + @Schema(description = "主键id") + private Long exchangeId; + + @Schema(description = "用户id") + private Long userId; + + @Schema(description = "标题") + private String exchangeTitle; + + @Schema(description = "状态(1:正常 2:禁用)") + private Integer exchangeStatus; + + @Schema(description = "删除状态(0:否 1:是)") + private Integer deleteStatus; + + @Schema(description = "是否被精选(0:否 1:是)") + private Integer isSelected; + + @Schema(description = "阅读量") + private Integer readNum; + + @Schema(description = "收藏量") + private Integer collectNum; + + @Schema(description = "评论数") + private Integer commentNum; + + @Schema(description = "发表时间") + private LocalDateTime pushDate; + + @Schema(description = "最后一条评论时间") + private LocalDateTime lastCommentTime; + + @Schema(description = "内容") + private String exchangeContent; + + @Schema(description = "总结") + private String exchangeSummary; + + @Schema(description = "预览图片(逗号分隔)") + private String exchangeContentImage; + + @Schema(description = "预览视频(逗号分隔)") + private String exchangeContentVideo; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + + @Schema(description = "投票信息") + private List voteList; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeLabelVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeLabelVO.java new file mode 100644 index 0000000..bdd0cb2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeLabelVO.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-病例交流-标签 列表VO + * + * @Author xing + * @Date 2025-08-10 22:34:44 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeLabelVO { + + + @Schema(description = "主键id") + private Long exchangeLabelId; + + @Schema(description = "临床文章id") + private Long exchangeId; + + @Schema(description = "app唯一标识") + private String appIden; + + @Schema(description = "标签名称") + private String labelName; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVO.java new file mode 100644 index 0000000..76d24d1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVO.java @@ -0,0 +1,82 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import java.util.List; + +import lombok.Data; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleLabelVO; + +/** + * 病例库-病例交流 列表VO + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeVO { + + + @Schema(description = "主键id") + private Long exchangeId; + + @Schema(description = "用户id") + private Long userId; + + @Schema(description = "用户名称") + private String userName; + + @Schema(description = "医院名称") + private String hospitalName; + + @Schema(description = "标题") + private String exchangeTitle; + + @Schema(description = "状态(1:正常 2:禁用)") + private Integer exchangeStatus; + + @Schema(description = "删除状态(0:否 1:是)") + private Integer deleteStatus; + + @Schema(description = "是否被精选(0:否 1:是)") + private Integer isSelected; + + @Schema(description = "阅读量") + private Integer readNum; + + @Schema(description = "收藏量") + private Integer collectNum; + + @Schema(description = "评论数") + private Integer commentNum; + + @Schema(description = "发表时间") + private LocalDateTime pushDate; + + @Schema(description = "最后一条评论时间") + private LocalDateTime lastCommentTime; + + @Schema(description = "内容") + private String exchangeContent; + + @Schema(description = "总结") + private String exchangeSummary; + + @Schema(description = "预览图片(逗号分隔)") + private String exchangeContentImage; + + @Schema(description = "预览视频(逗号分隔)") + private String exchangeContentVideo; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + + @Schema(description = "标签数据") + private List caseExchangeLabel; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteDetailVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteDetailVO.java new file mode 100644 index 0000000..566a1af --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteDetailVO.java @@ -0,0 +1,39 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import java.util.List; +import lombok.Data; + +/** + * 病例交流-投票详情 VO + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeVoteDetailVO { + + @Schema(description = "投票id") + private Long voteId; + + @Schema(description = "病例交流id") + private Long exchangeId; + + @Schema(description = "选项标题") + private String voteTitle; + + @Schema(description = "结束投票时间") + private LocalDateTime endTime; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + + @Schema(description = "投票选项列表") + private List optionList; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteOptionVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteOptionVO.java new file mode 100644 index 0000000..f9b95bb --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteOptionVO.java @@ -0,0 +1,45 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例交流-投票详情 列表VO + * + * @Author xing + * @Date 2025-08-10 23:02:14 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeVoteOptionVO { + + + @Schema(description = "主键id") + private Long optionId; + + @Schema(description = "投票id") + private Long voteId; + + @Schema(description = "选项") + private String optionValue; + + @Schema(description = "票数") + private Integer voteNum; + + + /** + * 被选择占比 + */ + @JsonProperty("proportion") + private Integer proportion = 0; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteVO.java new file mode 100644 index 0000000..89a2bb6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/CaseExchangeVoteVO.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 病例库-病例交流-投票 列表VO + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ + +@Data +public class CaseExchangeVoteVO { + + + @Schema(description = "主键id") + private Long voteId; + + @Schema(description = "病例交流id") + private Long exchangeId; + + @Schema(description = "选项标题") + private String voteTitle; + + @Schema(description = "结束投票时间") + private LocalDateTime endTime; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/StatsCaseExchangeUserVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/StatsCaseExchangeUserVO.java new file mode 100644 index 0000000..4e9f2d2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/StatsCaseExchangeUserVO.java @@ -0,0 +1,43 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-病例交流-用户 列表VO + * + * @Author xing + * @Date 2025-08-10 23:39:56 + * @Copyright gdxz + */ + +@Data +public class StatsCaseExchangeUserVO { + + + @Schema(description = "主键id") + private Long statsId; + + @Schema(description = "用户id") + private Long userId; + + @Schema(description = "数量-病例交流") + private Integer exchangeNum; + + @Schema(description = "总阅读量-病例交流") + private Integer exchangeReadNum; + + @Schema(description = "总收藏量-病例交流") + private Integer exchangeCollectNum; + + @Schema(description = "总评论量-病例交流") + private Integer exchangeCommentNum; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/StatsCaseExchangeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/StatsCaseExchangeVO.java new file mode 100644 index 0000000..ede1547 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/domain/vo/StatsCaseExchangeVO.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.caseExchange.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-病例交流 列表VO + * + * @Author xing + * @Date 2025-08-10 23:39:27 + * @Copyright gdxz + */ + +@Data +public class StatsCaseExchangeVO { + + + @Schema(description = "主键id") + private Long statsId; + + @Schema(description = "数量-病例交流") + private Integer exchangeNum; + + @Schema(description = "总阅读量-病例交流") + private Integer exchangeReadNum; + + @Schema(description = "总收藏量-病例交流") + private Integer exchangeCollectNum; + + @Schema(description = "总评论量-病例交流") + private Integer exchangeCommentNum; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeLabelManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeLabelManager.java new file mode 100644 index 0000000..7784dd2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeLabelManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseExchange.manager; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeLabelEntity; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeLabelDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 病例库-病例交流-标签 Manager + * + * @Author xing + * @Date 2025-08-10 22:34:44 + * @Copyright gdxz + */ +@Service +public class CaseExchangeLabelManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeManager.java new file mode 100644 index 0000000..2ee6ee8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseExchange.manager; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeEntity; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 病例库-病例交流 Manager + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ +@Service +public class CaseExchangeManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeVoteManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeVoteManager.java new file mode 100644 index 0000000..56adbe1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeVoteManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseExchange.manager; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeVoteEntity; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeVoteDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 病例库-病例交流-投票 Manager + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ +@Service +public class CaseExchangeVoteManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeVoteOptionManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeVoteOptionManager.java new file mode 100644 index 0000000..af3c0c2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/CaseExchangeVoteOptionManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseExchange.manager; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeVoteOptionEntity; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeVoteOptionDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 病例交流-投票详情 Manager + * + * @Author xing + * @Date 2025-08-10 23:02:14 + * @Copyright gdxz + */ +@Service +public class CaseExchangeVoteOptionManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/StatsCaseExchangeManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/StatsCaseExchangeManager.java new file mode 100644 index 0000000..fcde001 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/StatsCaseExchangeManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseExchange.manager; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.StatsCaseExchangeEntity; +import net.lab1024.sa.admin.module.business.caseExchange.dao.StatsCaseExchangeDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 统计表-病例库-病例交流 Manager + * + * @Author xing + * @Date 2025-08-10 23:39:27 + * @Copyright gdxz + */ +@Service +public class StatsCaseExchangeManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/StatsCaseExchangeUserManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/StatsCaseExchangeUserManager.java new file mode 100644 index 0000000..837d065 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/manager/StatsCaseExchangeUserManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.caseExchange.manager; + +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.StatsCaseExchangeUserEntity; +import net.lab1024.sa.admin.module.business.caseExchange.dao.StatsCaseExchangeUserDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 统计表-病例库-病例交流-用户 Manager + * + * @Author xing + * @Date 2025-08-10 23:39:56 + * @Copyright gdxz + */ +@Service +public class StatsCaseExchangeUserManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeLabel.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeLabel.java new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeLabel.java @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeLabelService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeLabelService.java new file mode 100644 index 0000000..339948e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeLabelService.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.caseExchange.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeLabelDao; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeLabelEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeLabelQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeLabelVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 病例库-病例交流-标签 Service + * + * @Author xing + * @Date 2025-08-10 22:34:44 + * @Copyright gdxz + */ + +@Service +public class CaseExchangeLabelService { + + @Resource + private CaseExchangeLabelDao caseExchangeLabelDao; + + /** + * 分页查询 + */ + public PageResult queryPage(CaseExchangeLabelQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = caseExchangeLabelDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeService.java new file mode 100644 index 0000000..c7054c3 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeService.java @@ -0,0 +1,319 @@ +package net.lab1024.sa.admin.module.business.caseExchange.service; + +import java.util.List; +import java.util.Objects; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import net.lab1024.sa.admin.module.business.basicHospital.domain.entity.BasicHospitalEntity; +import net.lab1024.sa.admin.module.business.basicSensitiveWord.service.BasicSensitiveWordService; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleLabelEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleLabelVO; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.vo.CaseClinicalArticleVO; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.entity.CaseClinicalArticleAuthorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalArticleAuthor.domain.vo.CaseClinicalArticleAuthorVO; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.vo.CaseClinicalDoctorVO; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeDao; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeLabelDao; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeLabelEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeAddForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeUpdateForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeStatusUpdateForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeSelectedUpdateForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeLabelVO; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVO; +import net.lab1024.sa.admin.util.RegularUtil; +import net.lab1024.sa.admin.util.Replace; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 病例库-病例交流 Service + * + * @Author xing + * @Date 2025-08-08 18:28:17 + * @Copyright gdxz + */ + +@Service +public class CaseExchangeService { + + @Resource + private CaseExchangeDao caseExchangeDao; + + @Resource + private CaseExchangeLabelDao caseExchangeLabelDao; + + @Resource + private BasicSensitiveWordService basicSensitiveWordService; + + @Resource + private RegularUtil regularUtil; + + /** + * 分页查询 + */ + public PageResult queryPage(CaseExchangeQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = caseExchangeDao.queryPage(page, queryForm); + for (CaseExchangeVO vo : list) { + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseExchangeLabelEntity::getExchangeId, vo.getExchangeId()); + List caseExchangeLabels = caseExchangeLabelDao.selectList(labelQueryWrapper); + + // 转换为VO + List caseExchangeLabelVOs = SmartBeanUtil.copyList(caseExchangeLabels, CaseExchangeLabelVO.class); + vo.setCaseExchangeLabel(caseExchangeLabelVOs); + } + + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 添加 + */ + public ResponseDTO add(CaseExchangeAddForm addForm) { + CaseExchangeEntity caseExchangeEntity = SmartBeanUtil.copy(addForm, CaseExchangeEntity.class); + caseExchangeDao.insert(caseExchangeEntity); + + // 处理病例交流标签 + HandleExchangeLabel(caseExchangeEntity, addForm.getLabelList()); + + return ResponseDTO.ok(); + } + + /** + * 更新 + * + */ + public ResponseDTO update(CaseExchangeUpdateForm updateForm) { + CaseExchangeEntity caseExchange = caseExchangeDao.selectById(updateForm.getExchangeId()); + if (caseExchange == null) { + throw new BusinessException("修改失败"); + } + + // 修改 + if (!Objects.equals(caseExchange.getExchangeTitle(), updateForm.getExchangeTitle())) { + caseExchange.setExchangeTitle(updateForm.getExchangeTitle()); + } + + if (!Objects.equals(caseExchange.getPushDate(), updateForm.getPushDate())) { + caseExchange.setPushDate(updateForm.getPushDate()); + } + + if (!Objects.equals(caseExchange.getExchangeContent(), updateForm.getExchangeContent())) { + caseExchange.setExchangeContent(updateForm.getExchangeContent()); + } + + if (!Objects.equals(caseExchange.getExchangeSummary(), updateForm.getExchangeSummary())) { + caseExchange.setExchangeSummary(updateForm.getExchangeSummary()); + } + + // 处理违法内容 + BasicSensitiveWordService.FilterResult result = basicSensitiveWordService.filter(updateForm.getExchangeContent()); + if (result.hasSensitive == 1){ + throw new BusinessException("内容中存在敏感词,请修改后提交"); + } + + if (updateForm.getExchangeSummary() != null){ + result = basicSensitiveWordService.filter(updateForm.getExchangeSummary()); + if (result.hasSensitive == 1){ + throw new BusinessException("总结中存在敏感词,请修改后提交"); + } + } + + // 匹配预览视频 + List videoUrls = regularUtil.extractOssVideosUrls(updateForm.getExchangeContent()); + videoUrls.replaceAll(Replace::removeOssDomain); + String exchangeContentVideo = String.join(",", videoUrls); + + String exchangeContentImage = ""; + if (exchangeContentVideo.isEmpty()){ + // 匹配预览图片 + List imageUrls = regularUtil.extractOssImageUrls(updateForm.getExchangeContent()); + imageUrls.replaceAll(Replace::removeOssDomain); + exchangeContentImage = String.join(",", imageUrls); + }else{ + exchangeContentImage = ""; + } + + if (!Objects.equals(caseExchange.getExchangeContentImage(), exchangeContentImage)) { + caseExchange.setExchangeContentImage(exchangeContentImage); + } + + if (!Objects.equals(caseExchange.getExchangeContentVideo(), exchangeContentVideo)) { + caseExchange.setExchangeContentVideo(exchangeContentVideo); + } + + caseExchangeDao.updateById(caseExchange); + + + // 删除标签 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseExchangeLabelEntity::getExchangeId, caseExchange.getExchangeId()); + caseExchangeLabelDao.delete(labelQueryWrapper); + + // 新增标签 + if (updateForm.getLabelList() != null && !updateForm.getLabelList().isEmpty()){ + // 验证标签数据-暂时无法验证,病例库不存标签库 + List caseExchangeLabel = updateForm.getLabelList(); + for (CaseExchangeUpdateForm.CaseExchangeLabelForm label : caseExchangeLabel ){ + CaseExchangeLabelEntity caseExchangeLabelData = new CaseExchangeLabelEntity(); + caseExchangeLabelData.setExchangeId(caseExchange.getExchangeId()); + caseExchangeLabelData.setAppIden(label.getAppIden()); + caseExchangeLabelData.setLabelName(label.getLabelName()); + int res = caseExchangeLabelDao.insert(caseExchangeLabelData); + if (res <= 0){ + throw new BusinessException("操作失败"); + } + } + } + + return ResponseDTO.ok(); + } + + /** + * 批量删除 + */ + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)){ + return ResponseDTO.ok(); + } + + caseExchangeDao.deleteBatchIds(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + */ + public ResponseDTO delete(Long exchangeId) { + if (null == exchangeId){ + return ResponseDTO.ok(); + } + + caseExchangeDao.deleteById(exchangeId); + return ResponseDTO.ok(); + } + + /** + * 获取详情 + */ + public ResponseDTO getDetail(Long exchangeId) { + if (null == exchangeId){ + return ResponseDTO.userErrorParam("病例交流ID不能为空"); + } + + CaseExchangeEntity entity = caseExchangeDao.selectById(exchangeId); + if (entity == null) { + return ResponseDTO.userErrorParam("病例交流不存在"); + } + + CaseExchangeVO vo = SmartBeanUtil.copy(entity, CaseExchangeVO.class); + + // 获取标签数据 + LambdaQueryWrapper labelQueryWrapper = new LambdaQueryWrapper<>(); + labelQueryWrapper.eq(CaseExchangeLabelEntity::getExchangeId, vo.getExchangeId()); + List caseExchangeLabels = caseExchangeLabelDao.selectList(labelQueryWrapper); + + // 转换为VO + List caseExchangeLabelVOs = SmartBeanUtil.copyList(caseExchangeLabels, CaseExchangeLabelVO.class); + vo.setCaseExchangeLabel(caseExchangeLabelVOs); + + return ResponseDTO.ok(vo); + } + + /** + * 更新状态 + */ + public ResponseDTO updateStatus(Long exchangeId, Integer status) { + if (null == exchangeId) { + return ResponseDTO.userErrorParam("病例交流ID不能为空"); + } + + CaseExchangeEntity caseExchange = caseExchangeDao.selectById(exchangeId); + if (caseExchange == null) { + return ResponseDTO.userErrorParam("病例交流不存在"); + } + + // 如果状态没有变化,直接返回 + if (Objects.equals(caseExchange.getExchangeStatus(), status)) { + return ResponseDTO.ok(); + } + + // 更新状态 + caseExchange.setExchangeStatus(status); + caseExchangeDao.updateById(caseExchange); + + return ResponseDTO.ok(); + } + + /** + * 更新精选状态 + */ + public ResponseDTO updateSelected(Long exchangeId, Integer isSelected) { + if (null == exchangeId) { + return ResponseDTO.userErrorParam("病例交流ID不能为空"); + } + + CaseExchangeEntity caseExchange = caseExchangeDao.selectById(exchangeId); + if (caseExchange == null) { + return ResponseDTO.userErrorParam("病例交流不存在"); + } + + // 如果精选状态没有变化,直接返回 + if (Objects.equals(caseExchange.getIsSelected(), isSelected)) { + return ResponseDTO.ok(); + } + + // 更新精选状态 + caseExchange.setIsSelected(isSelected); + caseExchangeDao.updateById(caseExchange); + + return ResponseDTO.ok(); + } + + /** + * 处理病例交流标签 + */ + private void HandleExchangeLabel(CaseExchangeEntity caseExchange, List labelList) { + if (CollectionUtils.isEmpty(labelList)) { + return; + } + + // 先删除原有的标签 + LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); + deleteWrapper.eq(CaseExchangeLabelEntity::getExchangeId, caseExchange.getExchangeId()); + caseExchangeLabelDao.delete(deleteWrapper); + + // 添加新的标签 + for (Object labelObj : labelList) { + CaseExchangeLabelEntity labelEntity = new CaseExchangeLabelEntity(); + labelEntity.setExchangeId(caseExchange.getExchangeId()); + + if (labelObj instanceof CaseExchangeAddForm.CaseExchangeLabelForm) { + CaseExchangeAddForm.CaseExchangeLabelForm label = (CaseExchangeAddForm.CaseExchangeLabelForm) labelObj; + labelEntity.setAppIden(label.getAppIden()); + labelEntity.setLabelName(label.getLabelName()); + } else if (labelObj instanceof CaseExchangeUpdateForm.CaseExchangeLabelForm) { + CaseExchangeUpdateForm.CaseExchangeLabelForm label = (CaseExchangeUpdateForm.CaseExchangeLabelForm) labelObj; + labelEntity.setAppIden(label.getAppIden()); + labelEntity.setLabelName(label.getLabelName()); + } + + caseExchangeLabelDao.insert(labelEntity); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeVoteOptionService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeVoteOptionService.java new file mode 100644 index 0000000..c8e7fb4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeVoteOptionService.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.caseExchange.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeVoteOptionDao; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeVoteOptionEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeVoteOptionQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteOptionVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 病例交流-投票详情 Service + * + * @Author xing + * @Date 2025-08-10 23:02:14 + * @Copyright gdxz + */ + +@Service +public class CaseExchangeVoteOptionService { + + @Resource + private CaseExchangeVoteOptionDao caseExchangeVoteOptionDao; + + /** + * 分页查询 + */ + public PageResult queryPage(CaseExchangeVoteOptionQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = caseExchangeVoteOptionDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeVoteService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeVoteService.java new file mode 100644 index 0000000..1295e65 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/CaseExchangeVoteService.java @@ -0,0 +1,162 @@ +package net.lab1024.sa.admin.module.business.caseExchange.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeVoteDao; +import net.lab1024.sa.admin.module.business.caseExchange.dao.CaseExchangeVoteOptionDao; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeVoteEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.CaseExchangeVoteOptionEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeVoteQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.CaseExchangeVoteUpdateForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteVO; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteDetailVO; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.CaseExchangeVoteOptionVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import jakarta.annotation.Resource; + +/** + * 病例库-病例交流-投票 Service + * + * @Author xing + * @Date 2025-08-10 22:37:20 + * @Copyright gdxz + */ + +@Service +public class CaseExchangeVoteService { + + @Resource + private CaseExchangeVoteDao caseExchangeVoteDao; + + @Resource + private CaseExchangeVoteOptionDao caseExchangeVoteOptionDao; + + /** + * 分页查询 + */ + public PageResult queryPage(CaseExchangeVoteQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = caseExchangeVoteDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 根据病例交流ID获取投票详情 + */ + public ResponseDTO getVoteDetailByExchangeId(Long exchangeId) { + if (exchangeId == null) { + return ResponseDTO.userErrorParam("病例交流ID不能为空"); + } + + CaseExchangeVoteDetailVO voteDetail = caseExchangeVoteDao.getVoteDetailByExchangeId(exchangeId); + if (voteDetail == null) { + return ResponseDTO.ok(null); + } + + // 获取投票选项列表 + List optionList = caseExchangeVoteOptionDao.getOptionsByVoteId(voteDetail.getVoteId()); + voteDetail.setOptionList(optionList); + + // 处理投票数据 + Integer voteNum = 0; + for (CaseExchangeVoteOptionVO dto : optionList){ + voteNum += dto.getVoteNum(); + } + + for (CaseExchangeVoteOptionVO dto : optionList){ + Integer proportion = (int) (Math.round((double) dto.getVoteNum() / voteNum * 10000) / 100.0); + dto.setProportion(proportion); + } + + return ResponseDTO.ok(voteDetail); + } + + /** + * 更新投票信息 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO updateVote(CaseExchangeVoteUpdateForm updateForm) { + if (updateForm == null) { + return ResponseDTO.userErrorParam("投票信息不能为空"); + } + + if (updateForm.getExchangeId() == null) { + return ResponseDTO.userErrorParam("病例交流ID不能为空"); + } + + // 如果投票ID为空,说明是新建投票 + if (updateForm.getVoteId() == null) { + return createVote(updateForm); + } else { + return updateExistingVote(updateForm); + } + } + + /** + * 创建新投票 + */ + private ResponseDTO createVote(CaseExchangeVoteUpdateForm updateForm) { + // 创建投票主表记录 + CaseExchangeVoteEntity voteEntity = new CaseExchangeVoteEntity(); + voteEntity.setExchangeId(updateForm.getExchangeId()); + voteEntity.setVoteTitle(updateForm.getVoteTitle()); + voteEntity.setEndTime(updateForm.getEndTime()); + + caseExchangeVoteDao.insert(voteEntity); + + // 创建投票选项 + if (CollectionUtils.isNotEmpty(updateForm.getOptionList())) { + for (CaseExchangeVoteUpdateForm.VoteOptionForm optionForm : updateForm.getOptionList()) { + CaseExchangeVoteOptionEntity optionEntity = new CaseExchangeVoteOptionEntity(); + optionEntity.setVoteId(voteEntity.getVoteId()); + optionEntity.setOptionValue(optionForm.getOptionValue()); + optionEntity.setVoteNum(optionForm.getVoteNum() != null ? optionForm.getVoteNum() : 0); + + caseExchangeVoteOptionDao.insert(optionEntity); + } + } + + return ResponseDTO.ok(); + } + + /** + * 更新现有投票 + */ + private ResponseDTO updateExistingVote(CaseExchangeVoteUpdateForm updateForm) { + // 更新投票主表记录 + CaseExchangeVoteEntity voteEntity = caseExchangeVoteDao.selectById(updateForm.getVoteId()); + if (voteEntity == null) { + return ResponseDTO.userErrorParam("投票不存在"); + } + + voteEntity.setVoteTitle(updateForm.getVoteTitle()); + voteEntity.setEndTime(updateForm.getEndTime()); + + caseExchangeVoteDao.updateById(voteEntity); + + // 删除现有选项 + caseExchangeVoteOptionDao.deleteByVoteId(updateForm.getVoteId()); + + // 重新创建投票选项 + if (CollectionUtils.isNotEmpty(updateForm.getOptionList())) { + for (CaseExchangeVoteUpdateForm.VoteOptionForm optionForm : updateForm.getOptionList()) { + CaseExchangeVoteOptionEntity optionEntity = new CaseExchangeVoteOptionEntity(); + optionEntity.setVoteId(voteEntity.getVoteId()); + optionEntity.setOptionValue(optionForm.getOptionValue()); + optionEntity.setVoteNum(optionForm.getVoteNum() != null ? optionForm.getVoteNum() : 0); + + caseExchangeVoteOptionDao.insert(optionEntity); + } + } + + return ResponseDTO.ok(); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/StatsCaseExchangeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/StatsCaseExchangeService.java new file mode 100644 index 0000000..77d1c6b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/StatsCaseExchangeService.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.caseExchange.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.dao.StatsCaseExchangeDao; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.StatsCaseExchangeEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.StatsCaseExchangeQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.StatsCaseExchangeVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 统计表-病例库-病例交流 Service + * + * @Author xing + * @Date 2025-08-10 23:39:27 + * @Copyright gdxz + */ + +@Service +public class StatsCaseExchangeService { + + @Resource + private StatsCaseExchangeDao statsCaseExchangeDao; + + /** + * 分页查询 + */ + public PageResult queryPage(StatsCaseExchangeQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = statsCaseExchangeDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/StatsCaseExchangeUserService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/StatsCaseExchangeUserService.java new file mode 100644 index 0000000..b52b6e9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/caseExchange/service/StatsCaseExchangeUserService.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.caseExchange.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.caseExchange.dao.StatsCaseExchangeUserDao; +import net.lab1024.sa.admin.module.business.caseExchange.domain.entity.StatsCaseExchangeUserEntity; +import net.lab1024.sa.admin.module.business.caseExchange.domain.form.StatsCaseExchangeUserQueryForm; +import net.lab1024.sa.admin.module.business.caseExchange.domain.vo.StatsCaseExchangeUserVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 统计表-病例库-病例交流-用户 Service + * + * @Author xing + * @Date 2025-08-10 23:39:56 + * @Copyright gdxz + */ + +@Service +public class StatsCaseExchangeUserService { + + @Resource + private StatsCaseExchangeUserDao statsCaseExchangeUserDao; + + /** + * 分页查询 + */ + public PageResult queryPage(StatsCaseExchangeUserQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = statsCaseExchangeUserDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/constant/CategoryTypeEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/constant/CategoryTypeEnum.java new file mode 100644 index 0000000..c3be511 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/constant/CategoryTypeEnum.java @@ -0,0 +1,36 @@ +package net.lab1024.sa.admin.module.business.category.constant; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 分类类型 枚举 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@AllArgsConstructor +@Getter +public enum CategoryTypeEnum implements BaseEnum { + + /** + * 1 商品 + */ + GOODS(1, "商品"), + + /** + * 2 自定义 + */ + CUSTOM(2, "自定义"), + + ; + + private final Integer value; + + private final String desc; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/controller/CategoryController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/controller/CategoryController.java new file mode 100644 index 0000000..2c7ff73 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/controller/CategoryController.java @@ -0,0 +1,69 @@ +package net.lab1024.sa.admin.module.business.category.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.business.category.domain.form.CategoryAddForm; +import net.lab1024.sa.admin.module.business.category.domain.form.CategoryTreeQueryForm; +import net.lab1024.sa.admin.module.business.category.domain.form.CategoryUpdateForm; +import net.lab1024.sa.admin.module.business.category.domain.vo.CategoryTreeVO; +import net.lab1024.sa.admin.module.business.category.domain.vo.CategoryVO; +import net.lab1024.sa.admin.module.business.category.service.CategoryService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 类目 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.Business.MANAGER_CATEGORY) +public class CategoryController { + + @Resource + private CategoryService categoryService; + + @Operation(summary = "添加类目 @author 胡克") + @PostMapping("/category/add") + @SaCheckPermission("category:add") + public ResponseDTO add(@RequestBody @Valid CategoryAddForm addForm) { + return categoryService.add(addForm); + } + + @Operation(summary = "更新类目 @author 胡克") + @PostMapping("/category/update") + @SaCheckPermission("category:update") + public ResponseDTO update(@RequestBody @Valid CategoryUpdateForm updateForm) { + return categoryService.update(updateForm); + } + + @Operation(summary = "查询类目详情 @author 胡克") + @GetMapping("/category/{categoryId}") + public ResponseDTO queryDetail(@PathVariable Long categoryId) { + return categoryService.queryDetail(categoryId); + } + + @Operation(summary = "查询类目层级树 @author 胡克") + @PostMapping("/category/tree") + @SaCheckPermission("category:tree") + public ResponseDTO> queryTree(@RequestBody @Valid CategoryTreeQueryForm queryForm) { + return categoryService.queryTree(queryForm); + } + + @Operation(summary = "删除类目 @author 胡克") + @GetMapping("/category/delete/{categoryId}") + @SaCheckPermission("category:delete") + public ResponseDTO delete(@PathVariable Long categoryId) { + return categoryService.delete(categoryId); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/dao/CategoryDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/dao/CategoryDao.java new file mode 100644 index 0000000..c107b26 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/dao/CategoryDao.java @@ -0,0 +1,62 @@ +package net.lab1024.sa.admin.module.business.category.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.lab1024.sa.admin.module.business.category.constant.CategoryTypeEnum; +import net.lab1024.sa.admin.module.business.category.domain.entity.CategoryEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 类目 dao + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface CategoryDao extends BaseMapper { + + /** + * 根据父级id 类型 查询子类 + * + * @param parentIdList 父级id集合 + * @param deletedFlag 删除标识 + * @return 列表 + */ + List queryByParentId(@Param("parentIdList") List parentIdList, + @Param("deletedFlag") Boolean deletedFlag); + + /** + * 根据父级id 类型 查询子类 + * + * @param parentIdList 父级id集合 + * @param categoryType {@link CategoryTypeEnum} + * @param deletedFlag 删除标识 + * @return 列表 + */ + List queryByParentIdAndType(@Param("parentIdList") List parentIdList, + @Param("categoryType") Integer categoryType, + @Param("deletedFlag") Boolean deletedFlag); + + /** + * 某个类型的所有 + */ + List queryByType(@Param("categoryType") Integer categoryType, + @Param("deletedFlag") Boolean deletedFlag); + + /** + * 根据类型和id查询 + */ + CategoryEntity selectByTypeAndId(@Param("categoryType") Integer categoryType, @Param("categoryId") Long categoryId); + + /** + * 查看类目 具体条件 看sql + */ + CategoryEntity selectOne(CategoryEntity entity); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/dto/CategoryBaseDTO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/dto/CategoryBaseDTO.java new file mode 100644 index 0000000..4849d60 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/dto/CategoryBaseDTO.java @@ -0,0 +1,43 @@ +package net.lab1024.sa.admin.module.business.category.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.admin.module.business.category.constant.CategoryTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import org.hibernate.validator.constraints.Length; + +/** + * 类目 基础属性 DTO 类 + * + * @author 胡克 + * @date 2021/1/20 16:17 + */ +@Data +public class CategoryBaseDTO { + + @Schema(description = "类目名称", required = true) + @NotBlank(message = "类目名称不能为空") + @Length(max = 20, message = "类目名称最多20字符") + private String categoryName; + + @SchemaEnum(desc = "分类类型", value = CategoryTypeEnum.class) + @CheckEnum(value = CategoryTypeEnum.class, required = true, message = "分类错误") + private Integer categoryType; + + @Schema(description = "父级类目id|可选") + private Long parentId; + + @Schema(description = "排序|可选") + private Integer sort; + + @Schema(description = "备注|可选") + @Length(max = 200, message = "备注最多200字符") + private String remark; + + @Schema(description = "禁用状态") + @NotNull(message = "禁用状态不能为空") + private Boolean disabledFlag; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/dto/CategorySimpleDTO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/dto/CategorySimpleDTO.java new file mode 100644 index 0000000..97d0310 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/dto/CategorySimpleDTO.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.category.domain.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 类目 基础属性 DTO 类 + * + * @author 胡克 + * @date 2021/1/20 16:17 + */ +@Data +public class CategorySimpleDTO { + + @Schema(description = "类目id") + private Long categoryId; + + @Schema(description = "类目名称") + private String categoryName; + + @Schema(description = "类目层级全称") + private String categoryFullName; + + @Schema(description = "父级id") + private Long parentId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/entity/CategoryEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/entity/CategoryEntity.java new file mode 100644 index 0000000..76df14d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/entity/CategoryEntity.java @@ -0,0 +1,70 @@ +package net.lab1024.sa.admin.module.business.category.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import net.lab1024.sa.admin.module.business.category.constant.CategoryTypeEnum; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 类目 实体类 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_category") +public class CategoryEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.AUTO) + private Long categoryId; + + /** + * 类目名称 + */ + private String categoryName; + + /** + * 类目 类型 + * + * @see CategoryTypeEnum + */ + private Integer categoryType; + + /** + * 父级类目id + */ + private Long parentId; + + /** + * 是否禁用 + */ + private Boolean disabledFlag; + + /** + * 排序 + */ + private Integer sort; + + /** + * 删除状态 + */ + private Boolean deletedFlag; + + /** + * 备注 + */ + private String remark; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryAddForm.java new file mode 100644 index 0000000..df2a169 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryAddForm.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.business.category.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.admin.module.business.category.constant.CategoryTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import org.hibernate.validator.constraints.Length; + +/** + * 类目 添加 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class CategoryAddForm { + + @Schema(description = "类目名称", required = true) + @NotBlank(message = "类目名称不能为空") + @Length(max = 20, message = "类目名称最多20字符") + private String categoryName; + + @SchemaEnum(desc = "分类类型", value = CategoryTypeEnum.class) + @CheckEnum(value = CategoryTypeEnum.class, required = true, message = "分类错误") + private Integer categoryType; + + @Schema(description = "父级类目id|可选") + private Long parentId; + + @Schema(description = "排序|可选") + private Integer sort; + + @Schema(description = "备注|可选") + @Length(max = 200, message = "备注最多200字符") + private String remark; + + @Schema(description = "禁用状态") + @NotNull(message = "禁用状态不能为空") + private Boolean disabledFlag; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryTreeQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryTreeQueryForm.java new file mode 100644 index 0000000..87bf072 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryTreeQueryForm.java @@ -0,0 +1,25 @@ +package net.lab1024.sa.admin.module.business.category.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.business.category.constant.CategoryTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; + +/** + * 类目 层级树查询 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class CategoryTreeQueryForm { + + @SchemaEnum(desc = "分类类型|可选", value = CategoryTypeEnum.class) + private Integer categoryType; + + @Schema(description = "父级类目id|可选") + private Long parentId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryUpdateForm.java new file mode 100644 index 0000000..bfa4491 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/form/CategoryUpdateForm.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.business.category.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 类目 更新 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class CategoryUpdateForm extends CategoryAddForm { + + @Schema(description = "类目id") + @NotNull(message = "类目id不能为空") + private Long categoryId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/vo/CategoryTreeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/vo/CategoryTreeVO.java new file mode 100644 index 0000000..f847b40 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/vo/CategoryTreeVO.java @@ -0,0 +1,43 @@ +package net.lab1024.sa.admin.module.business.category.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 类目 层级树 vo + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class CategoryTreeVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "类目id") + private Long categoryId; + + @Schema(description = "类目名称") + private String categoryName; + + @Schema(description = "类目层级全称") + private String categoryFullName; + + @Schema(description = "父级id") + private Long parentId; + + @Schema(description = "类目id") + private Long value; + + @Schema(description = "类目名称") + private String label; + + @Schema(description = "子类") + private List children; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/vo/CategoryVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/vo/CategoryVO.java new file mode 100644 index 0000000..1436958 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/domain/vo/CategoryVO.java @@ -0,0 +1,46 @@ +package net.lab1024.sa.admin.module.business.category.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.business.category.constant.CategoryTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; + +import java.time.LocalDateTime; + +/** + * 类目 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class CategoryVO { + + @Schema(description = "类目名称", required = true) + private String categoryName; + + @SchemaEnum(desc = "分类类型", value = CategoryTypeEnum.class) + private Integer categoryType; + + @Schema(description = "父级类目id|可选") + private Long parentId; + + @Schema(description = "排序|可选") + private Integer sort; + + @Schema(description = "备注|可选") + private String remark; + + @Schema(description = "禁用状态") + private Boolean disabledFlag; + + @Schema(description = "类目id") + private Long categoryId; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/manager/CategoryCacheManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/manager/CategoryCacheManager.java new file mode 100644 index 0000000..72a2be6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/manager/CategoryCacheManager.java @@ -0,0 +1,113 @@ +package net.lab1024.sa.admin.module.business.category.manager; + +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.constant.AdminCacheConst; +import net.lab1024.sa.admin.module.business.category.dao.CategoryDao; +import net.lab1024.sa.admin.module.business.category.domain.entity.CategoryEntity; +import net.lab1024.sa.admin.module.business.category.domain.vo.CategoryTreeVO; +import net.lab1024.sa.base.common.constant.StringConst; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 类目 查询 缓存 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +@Slf4j +public class CategoryCacheManager { + + + @Resource + private CategoryDao categoryDao; + + + /** + * 根据类目id 移除缓存 + */ + @CacheEvict(value = {AdminCacheConst.Category.CATEGORY_ENTITY, AdminCacheConst.Category.CATEGORY_SUB, AdminCacheConst.Category.CATEGORY_TREE}, allEntries = true) + public void removeCache() { + log.info("clear CATEGORY ,CATEGORY_SUB ,CATEGORY_TREE"); + } + + /** + * 查詢类目 + * + */ + @Cacheable(AdminCacheConst.Category.CATEGORY_ENTITY) + public CategoryEntity queryCategory(Long categoryId) { + return categoryDao.selectById(categoryId); + } + + /** + * 查询类目 子级 + * + */ + @Cacheable(AdminCacheConst.Category.CATEGORY_SUB) + public List querySubCategory(Long categoryId) { + return categoryDao.queryByParentId(Lists.newArrayList(categoryId), false); + } + + + /** + * 查询类目 层级树 + * 优先查询缓存 + */ + @Cacheable(AdminCacheConst.Category.CATEGORY_TREE) + public List queryCategoryTree(Long parentId, Integer categoryType) { + List allCategoryEntityList = categoryDao.queryByType(categoryType, false); + + List categoryEntityList = allCategoryEntityList.stream().filter(e -> e.getParentId().equals(parentId)).collect(Collectors.toList()); + List treeList = SmartBeanUtil.copyList(categoryEntityList, CategoryTreeVO.class); + treeList.forEach(e -> { + e.setLabel(e.getCategoryName()); + e.setValue(e.getCategoryId()); + e.setCategoryFullName(e.getCategoryName()); + }); + // 递归设置子类 + this.queryAndSetSubCategory(treeList, allCategoryEntityList); + return treeList; + } + + /** + * 递归查询设置类目子类 + * 从缓存查询子类 + * + */ + private void queryAndSetSubCategory(List treeList, List allCategoryEntityList) { + if (CollectionUtils.isEmpty(treeList)) { + return; + } + List parentIdList = treeList.stream().map(CategoryTreeVO::getValue).collect(Collectors.toList()); + List categoryEntityList = allCategoryEntityList.stream().filter(e -> parentIdList.contains(e.getParentId())).collect(Collectors.toList()); + Map> categorySubMap = categoryEntityList.stream().collect(Collectors.groupingBy(CategoryEntity::getParentId)); + treeList.forEach(e -> { + List childrenEntityList = categorySubMap.getOrDefault(e.getValue(), Lists.newArrayList()); + List childrenVOList = SmartBeanUtil.copyList(childrenEntityList, CategoryTreeVO.class); + childrenVOList.forEach(item -> { + item.setLabel(item.getCategoryName()); + item.setValue(item.getCategoryId()); + item.setCategoryFullName(e.getCategoryFullName() + StringConst.SEPARATOR_SLASH + item.getCategoryName()); + }); + // 递归查询 + this.queryAndSetSubCategory(childrenVOList, allCategoryEntityList); + e.setChildren(childrenVOList); + }); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/service/CategoryQueryService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/service/CategoryQueryService.java new file mode 100644 index 0000000..9def152 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/service/CategoryQueryService.java @@ -0,0 +1,188 @@ +package net.lab1024.sa.admin.module.business.category.service; + +import cn.hutool.core.util.StrUtil; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.module.business.category.domain.dto.CategorySimpleDTO; +import net.lab1024.sa.admin.module.business.category.domain.entity.CategoryEntity; +import net.lab1024.sa.admin.module.business.category.manager.CategoryCacheManager; +import net.lab1024.sa.base.common.constant.StringConst; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 类目 查询 业务类 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +@Slf4j +public class CategoryQueryService { + + private static final Long DEFAULT_CATEGORY_PARENT_ID = 0L; + + @Resource + private CategoryCacheManager categoryCacheManager; + + /** + * 根据 id 查询未删除的类目 + * + * @param categoryId + * @return 可能 null + */ + public Optional queryCategory(Long categoryId) { + if (null == categoryId) { + return Optional.empty(); + } + CategoryEntity entity = categoryCacheManager.queryCategory(categoryId); + if (null == entity || entity.getDeletedFlag()) { + return Optional.empty(); + } + return Optional.of(entity); + } + + + /** + * 根据 类目id集合 查询未删除的类目集合 + */ + public Map queryCategoryList(List categoryIdList) { + if (CollectionUtils.isEmpty(categoryIdList)) { + return Collections.emptyMap(); + } + categoryIdList = categoryIdList.stream().distinct().collect(Collectors.toList()); + Map categoryEntityMap = Maps.newHashMap(); + for (Long categoryId : categoryIdList) { + CategoryEntity categoryEntity = categoryCacheManager.queryCategory(categoryId); + if (categoryEntity != null) { + categoryEntityMap.put(categoryId, categoryEntity); + } + } + return categoryEntityMap; + } + + + /** + * 根据类目id 递归查询该id的所有子类id 递归查询 + * 同时存入缓存 + * 注意:查询出来的集合 不包含传递的父类参数 + */ + public List queryCategorySubId(List categoryIdList) { + if (CollectionUtils.isEmpty(categoryIdList)) { + return Collections.emptyList(); + } + //所有子类 + List categoryEntityList = Lists.newArrayList(); + categoryIdList.forEach(e -> { + categoryEntityList.addAll(categoryCacheManager.querySubCategory(e)); + }); + Map> subTypeMap = categoryEntityList.stream().collect(Collectors.groupingBy(CategoryEntity::getCategoryId)); + // 递归查询子类 + categoryIdList = subTypeMap.values().stream().flatMap(Collection::stream).map(CategoryEntity::getCategoryId).distinct().collect(Collectors.toList()); + if (CollectionUtils.isEmpty(categoryIdList)) { + return Lists.newArrayList(); + } + categoryIdList.addAll(this.queryCategorySubId(categoryIdList)); + return categoryIdList; + } + + + /** + * 处理类目名称 + */ + public List queryCategoryName(List categoryIdList) { + if (CollectionUtils.isEmpty(categoryIdList)) { + return null; + } + Map categoryMap = this.queryCategoryList(categoryIdList); + List categoryNameList = Lists.newArrayList(); + categoryIdList.forEach(e -> { + CategoryEntity categoryEntity = categoryMap.get(e); + if (categoryEntity != null) { + categoryNameList.add(categoryMap.get(e).getCategoryName()); + } + }); + return categoryNameList; + } + + /** + * 根据类目id 查询类目名称 + */ + public String queryCategoryName(Long categoryId) { + CategoryEntity categoryEntity = categoryCacheManager.queryCategory(categoryId); + if (null == categoryEntity || categoryEntity.getDeletedFlag()) { + return null; + } + return categoryEntity.getCategoryName(); + } + + /** + * 根据类目id 查询类目详情 包含类目全称 如:医考/医师资格/临床执业 + */ + public CategorySimpleDTO queryCategoryInfo(Long categoryId) { + CategoryEntity categoryEntity = categoryCacheManager.queryCategory(categoryId); + if (null == categoryEntity || categoryEntity.getDeletedFlag()) { + return null; + } + String fullName = this.queryFullName(categoryId); + // 返回DTO + CategorySimpleDTO categoryDTO = new CategorySimpleDTO(); + categoryDTO.setCategoryId(categoryId); + categoryDTO.setCategoryName(categoryEntity.getCategoryName()); + categoryDTO.setCategoryFullName(fullName); + categoryDTO.setParentId(categoryEntity.getParentId()); + return categoryDTO; + } + + /** + * 递归查询分类和所有父级类目 + * ps:特别注意返回的集合中 包含自己 + */ + public List queryCategoryAndParent(Long categoryId) { + List parentCategoryList = Lists.newArrayList(); + CategoryEntity categoryEntity = categoryCacheManager.queryCategory(categoryId); + if (null == categoryEntity || categoryEntity.getDeletedFlag()) { + return parentCategoryList; + } + + // 父级始终放在第一位 + parentCategoryList.add(0, categoryEntity); + Long parentId = categoryEntity.getParentId(); + if (Objects.equals(DEFAULT_CATEGORY_PARENT_ID, parentId)) { + return parentCategoryList; + } + parentCategoryList.addAll(0, this.queryCategoryAndParent(parentId)); + return parentCategoryList; + } + + /** + * 查询 分类全称 如:医考/医师资格/临床执业 + */ + public String queryFullName(Long categoryId) { + List parentCategoryList = this.queryCategoryAndParent(categoryId); + // 拼接父级类目名称 斜杠分隔返回 + List nameList = parentCategoryList.stream().map(CategoryEntity::getCategoryName).collect(Collectors.toList()); + return StrUtil.join(StringConst.SEPARATOR_SLASH, nameList); + } + + /** + * 查询 分类全称 如:医考/医师资格/临床执业 + */ + public Map queryFullName(List categoryIdList) { + if (CollectionUtils.isEmpty(categoryIdList)) { + return Maps.newHashMap(); + } + // 循环内查询的缓存 还ok + return categoryIdList.stream().collect(Collectors.toMap(Function.identity(), this::queryFullName)); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/service/CategoryService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/service/CategoryService.java new file mode 100644 index 0000000..130b685 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/category/service/CategoryService.java @@ -0,0 +1,206 @@ +package net.lab1024.sa.admin.module.business.category.service; + +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.category.dao.CategoryDao; +import net.lab1024.sa.admin.module.business.category.domain.entity.CategoryEntity; +import net.lab1024.sa.admin.module.business.category.domain.form.CategoryAddForm; +import net.lab1024.sa.admin.module.business.category.domain.form.CategoryTreeQueryForm; +import net.lab1024.sa.admin.module.business.category.domain.form.CategoryUpdateForm; +import net.lab1024.sa.admin.module.business.category.domain.vo.CategoryTreeVO; +import net.lab1024.sa.admin.module.business.category.domain.vo.CategoryVO; +import net.lab1024.sa.admin.module.business.category.manager.CategoryCacheManager; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * 类目 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021/08/05 21:26:58 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class CategoryService { + + @Resource + private CategoryDao categoryDao; + + @Resource + private CategoryQueryService categoryQueryService; + + @Resource + private CategoryCacheManager categoryCacheManager; + + /** + * 添加类目 + */ + public ResponseDTO add(CategoryAddForm addForm) { + // 校验类目 + CategoryEntity categoryEntity = SmartBeanUtil.copy(addForm, CategoryEntity.class); + ResponseDTO res = this.checkCategory(categoryEntity, false); + if (!res.getOk()) { + return res; + } + // 没有父类则使用默认父类 + Long parentId = null == addForm.getParentId() ? NumberUtils.LONG_ZERO : addForm.getParentId(); + categoryEntity.setParentId(parentId); + categoryEntity.setSort(null == addForm.getSort() ? 0 : addForm.getSort()); + categoryEntity.setDeletedFlag(false); + + // 保存数据 + categoryDao.insert(categoryEntity); + + // 更新缓存 + categoryCacheManager.removeCache(); + return ResponseDTO.ok(); + } + + /** + * 更新类目 + * 不能更新父级类目 + * + */ + public ResponseDTO update(CategoryUpdateForm updateForm) { + // 校验类目 + Long categoryId = updateForm.getCategoryId(); + Optional optional = categoryQueryService.queryCategory(categoryId); + if (!optional.isPresent()) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + CategoryEntity categoryEntity = SmartBeanUtil.copy(updateForm, CategoryEntity.class); + + /* + 不更新类目类型 + 不更新父类id + */ + Integer categoryType = optional.get().getCategoryType(); + categoryEntity.setCategoryType(categoryType); + categoryEntity.setParentId(optional.get().getParentId()); + + ResponseDTO responseDTO = this.checkCategory(categoryEntity, true); + if (!responseDTO.getOk()) { + return responseDTO; + } + categoryDao.updateById(categoryEntity); + + // 更新缓存 + categoryCacheManager.removeCache(); + return ResponseDTO.ok(); + } + + /** + * 新增/更新 类目时的 校验 + * + */ + private ResponseDTO checkCategory(CategoryEntity categoryEntity, boolean isUpdate) { + // 校验父级是否存在 + Long parentId = categoryEntity.getParentId(); + Integer categoryType = categoryEntity.getCategoryType(); + if (null != parentId) { + if (Objects.equals(categoryEntity.getCategoryId(), parentId)) { + return ResponseDTO.userErrorParam("父级类目怎么和自己相同了"); + } + if (!Objects.equals(parentId, NumberUtils.LONG_ZERO)) { + Optional optional = categoryQueryService.queryCategory(parentId); + if (!optional.isPresent()) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST, "父级类目不存在~"); + } + + CategoryEntity parent = optional.get(); + if (!Objects.equals(categoryType, parent.getCategoryType())) { + return ResponseDTO.userErrorParam("与父级类目类型不一致"); + } + } + + } else { + // 如果没有父类 使用默认父类 + parentId = NumberUtils.LONG_ZERO; + } + + // 校验同父类下 名称是否重复 + CategoryEntity queryEntity = new CategoryEntity(); + queryEntity.setParentId(parentId); + queryEntity.setCategoryType(categoryType); + queryEntity.setCategoryName(categoryEntity.getCategoryName()); + queryEntity.setDeletedFlag(false); + queryEntity = categoryDao.selectOne(queryEntity); + if (null != queryEntity) { + if (isUpdate) { + if (!Objects.equals(queryEntity.getCategoryId(), categoryEntity.getCategoryId())) { + return ResponseDTO.userErrorParam("同级下已存在相同类目~"); + } + } else { + return ResponseDTO.userErrorParam("同级下已存在相同类目~"); + } + } + return ResponseDTO.ok(); + } + + /** + * 查询 类目详情 + * + */ + public ResponseDTO queryDetail(Long categoryId) { + Optional optional = categoryQueryService.queryCategory(categoryId); + if (!optional.isPresent()) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + CategoryVO adminVO = SmartBeanUtil.copy(optional.get(), CategoryVO.class); + return ResponseDTO.ok(adminVO); + } + + /** + * 根据父级id 查询所有子类 返回层级树 + * 如果父类id 为空 返回所有类目层级 + * + */ + public ResponseDTO> queryTree(CategoryTreeQueryForm queryForm) { + if (null == queryForm.getParentId()) { + if (null == queryForm.getCategoryType()) { + return ResponseDTO.userErrorParam("类目类型不能为空"); + } + queryForm.setParentId(NumberUtils.LONG_ZERO); + } + List treeList = categoryCacheManager.queryCategoryTree(queryForm.getParentId(), queryForm.getCategoryType()); + return ResponseDTO.ok(treeList); + } + + /** + * 删除类目 + * 如果有未删除的子类 则无法删除 + * + */ + public ResponseDTO delete(Long categoryId) { + Optional optional = categoryQueryService.queryCategory(categoryId); + if (!optional.isPresent()) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + + List categorySubId = categoryQueryService.queryCategorySubId(Lists.newArrayList(categoryId)); + if (CollectionUtils.isNotEmpty(categorySubId)) { + return ResponseDTO.userErrorParam("请先删除子级类目"); + } + + // 更新数据 + CategoryEntity categoryEntity = new CategoryEntity(); + categoryEntity.setCategoryId(categoryId); + categoryEntity.setDeletedFlag(true); + categoryDao.updateById(categoryEntity); + + // 更新缓存 + categoryCacheManager.removeCache(); + return ResponseDTO.ok(); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/constant/GoodsStatusEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/constant/GoodsStatusEnum.java new file mode 100644 index 0000000..95d37d5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/constant/GoodsStatusEnum.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.goods.constant; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 商品状态 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@AllArgsConstructor +@Getter +public enum GoodsStatusEnum implements BaseEnum { + + /** + * 1 预约中 + */ + APPOINTMENT(1, "预约中"), + + /** + * 2 售卖 + */ + SELL(2, "售卖中"), + + /** + * 3 售罄 + */ + SELL_OUT(3, "售罄"), + + + ; + + private final Integer value; + + private final String desc; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/controller/GoodsController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/controller/GoodsController.java new file mode 100644 index 0000000..42b69b0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/controller/GoodsController.java @@ -0,0 +1,94 @@ +package net.lab1024.sa.admin.module.business.goods.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsAddForm; +import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsQueryForm; +import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsUpdateForm; +import net.lab1024.sa.admin.module.business.goods.domain.vo.GoodsExcelVO; +import net.lab1024.sa.admin.module.business.goods.domain.vo.GoodsVO; +import net.lab1024.sa.admin.module.business.goods.service.GoodsService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.ValidateList; +import net.lab1024.sa.base.common.util.SmartExcelUtil; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * 商品业务 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.Business.MANAGER_GOODS) +public class GoodsController { + + @Resource + private GoodsService goodsService; + + @Operation(summary = "分页查询 @author 胡克") + @PostMapping("/goods/query") + @SaCheckPermission("goods:query") + public ResponseDTO> query(@RequestBody @Valid GoodsQueryForm queryForm) { + return goodsService.query(queryForm); + } + + @Operation(summary = "添加商品 @author 胡克") + @PostMapping("/goods/add") + @SaCheckPermission("goods:add") + public ResponseDTO add(@RequestBody @Valid GoodsAddForm addForm) { + return goodsService.add(addForm); + } + + @Operation(summary = "更新商品 @author 胡克") + @PostMapping("/goods/update") + @SaCheckPermission("goods:update") + public ResponseDTO update(@RequestBody @Valid GoodsUpdateForm updateForm) { + return goodsService.update(updateForm); + } + + @Operation(summary = "删除 @author 卓大") + @GetMapping("/goods/delete/{goodsId}") + @SaCheckPermission("goods:delete") + public ResponseDTO delete(@PathVariable Long goodsId) { + return goodsService.delete(goodsId); + } + + @Operation(summary = "批量 @author 卓大") + @PostMapping("/goods/batchDelete") + @SaCheckPermission("goods:batchDelete") + public ResponseDTO batchDelete(@RequestBody @Valid ValidateList idList) { + return goodsService.batchDelete(idList); + } + + // --------------- 导出和导入 ------------------- + + @Operation(summary = "导入 @author 卓大") + @PostMapping("/goods/importGoods") + @SaCheckPermission("goods:importGoods") + public ResponseDTO importGoods(@RequestParam MultipartFile file) { + return goodsService.importGoods(file); + } + + @Operation(summary = "导出 @author 卓大") + @GetMapping("/goods/exportGoods") + @SaCheckPermission("goods:exportGoods") + public void exportGoods(HttpServletResponse response) throws IOException { + List goodsList = goodsService.getAllGoods(); + SmartExcelUtil.exportExcel(response,"商品列表.xlsx","商品",GoodsExcelVO.class, goodsList); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/dao/GoodsDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/dao/GoodsDao.java new file mode 100644 index 0000000..932f480 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/dao/GoodsDao.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.business.goods.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.business.goods.domain.entity.GoodsEntity; +import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsQueryForm; +import net.lab1024.sa.admin.module.business.goods.domain.vo.GoodsVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 商品 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface GoodsDao extends BaseMapper { + + /** + * 分页 查询商品 + * + */ + List query(Page page, @Param("query") GoodsQueryForm query); + + /** + * 批量更新删除状态 + */ + + void batchUpdateDeleted(@Param("goodsIdList")List goodsIdList,@Param("deletedFlag")Boolean deletedFlag); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/entity/GoodsEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/entity/GoodsEntity.java new file mode 100644 index 0000000..d4ad21f --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/entity/GoodsEntity.java @@ -0,0 +1,71 @@ +package net.lab1024.sa.admin.module.business.goods.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 商品 实体类 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_goods") +public class GoodsEntity { + + @TableId(type = IdType.AUTO) + private Long goodsId; + + /** + * 商品状态:[1:预约中,2:售卖中,3:售罄] + */ + private Integer goodsStatus; + + /** + * 商品分类 + */ + private Long categoryId; + + /** + * 商品名称 + */ + private String goodsName; + + /** + * 产地 + */ + private String place; + + /** + * 商品价格 + */ + private BigDecimal price; + + + /** + * 上架状态 + */ + private Boolean shelvesFlag; + + /** + * 删除状态 + */ + private Boolean deletedFlag; + + /** + * 备注 + */ + private String remark; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsAddForm.java new file mode 100644 index 0000000..c13620c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsAddForm.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.admin.module.business.goods.domain.form; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.admin.module.business.goods.constant.GoodsStatusEnum; +import net.lab1024.sa.base.common.json.deserializer.DictDataDeserializer; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; + +import java.math.BigDecimal; + +/** + * 商品 添加表单 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class GoodsAddForm { + + @Schema(description = "商品分类") + @NotNull(message = "商品分类不能为空") + private Long categoryId; + + @Schema(description = "商品名称") + @NotBlank(message = "商品名称不能为空") + private String goodsName; + + @SchemaEnum(GoodsStatusEnum.class) + @CheckEnum(message = "商品状态错误", value = GoodsStatusEnum.class, required = true) + private Integer goodsStatus; + + @Schema(description = "产地") + @NotBlank(message = "产地 不能为空 ") + @JsonDeserialize(using = DictDataDeserializer.class) + private String place; + + @Schema(description = "商品价格") + @NotNull(message = "商品价格不能为空") + @DecimalMin(value = "0", message = "商品价格最低0") + private BigDecimal price; + + @Schema(description = "上架状态") + @NotNull(message = "上架状态不能为空") + private Boolean shelvesFlag; + + @Schema(description = "备注|可选") + private String remark; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsImportForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsImportForm.java new file mode 100644 index 0000000..d6ccbff --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsImportForm.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.business.goods.domain.form; + +import cn.idev.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 商品 导入表单 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class GoodsImportForm { + + @ExcelProperty("商品分类") + private String categoryName; + + @ExcelProperty("商品名称") + private String goodsName; + + @ExcelProperty("商品状态错误") + private String goodsStatus; + + @ExcelProperty("产地") + private String place; + + @ExcelProperty("商品价格") + private BigDecimal price; + + @ExcelProperty("备注") + private String remark; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsQueryForm.java new file mode 100644 index 0000000..7f9cc0e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsQueryForm.java @@ -0,0 +1,45 @@ +package net.lab1024.sa.admin.module.business.goods.domain.form; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.business.goods.constant.GoodsStatusEnum; +import net.lab1024.sa.base.common.domain.PageParam; +import net.lab1024.sa.base.common.json.deserializer.DictDataDeserializer; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import org.hibernate.validator.constraints.Length; + +/** + * 商品 分页查询 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class GoodsQueryForm extends PageParam { + + @Schema(description = "商品分类") + private Integer categoryId; + + @Schema(description = "搜索词") + @Length(max = 30, message = "搜索词最多30字符") + private String searchWord; + + @SchemaEnum(GoodsStatusEnum.class) + @CheckEnum(message = "商品状态错误", value = GoodsStatusEnum.class, required = false) + private Integer goodsStatus; + + @Schema(description = "产地") + @JsonDeserialize(using = DictDataDeserializer.class) + private String place; + + @Schema(description = "上架状态") + private Boolean shelvesFlag; + + @Schema(hidden = true) + private Boolean deletedFlag; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsUpdateForm.java new file mode 100644 index 0000000..4689653 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/form/GoodsUpdateForm.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.business.goods.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 商品 更新表单 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class GoodsUpdateForm extends GoodsAddForm { + + @Schema(description = "商品id") + @NotNull(message = "商品id不能为空") + private Long goodsId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/vo/GoodsExcelVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/vo/GoodsExcelVO.java new file mode 100644 index 0000000..98a29b1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/vo/GoodsExcelVO.java @@ -0,0 +1,44 @@ +package net.lab1024.sa.admin.module.business.goods.domain.vo; + + +import cn.idev.excel.annotation.ExcelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * excel商品 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class GoodsExcelVO { + + @ExcelProperty("商品分类") + private String categoryName; + + @ExcelProperty("商品名称") + private String goodsName; + + @ExcelProperty("商品状态错误") + private String goodsStatus; + + @ExcelProperty("产地") + private String place; + + @ExcelProperty("商品价格") + private BigDecimal price; + + @ExcelProperty("备注") + private String remark; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/vo/GoodsVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/vo/GoodsVO.java new file mode 100644 index 0000000..191965f --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/domain/vo/GoodsVO.java @@ -0,0 +1,53 @@ +package net.lab1024.sa.admin.module.business.goods.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.business.goods.constant.GoodsStatusEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 商品 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class GoodsVO { + + @Schema(description = "商品分类") + private Long categoryId; + + @Schema(description = "商品名称") + private String goodsName; + + @SchemaEnum(GoodsStatusEnum.class) + private Integer goodsStatus; + + @Schema(description = "产地") + private String place; + + @Schema(description = "商品价格") + private BigDecimal price; + + @Schema(description = "上架状态") + private Boolean shelvesFlag; + + @Schema(description = "备注|可选") + private String remark; + + @Schema(description = "商品id") + private Long goodsId; + + @Schema(description = "商品分类") + private String categoryName; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/service/GoodsService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/service/GoodsService.java new file mode 100644 index 0000000..e4d59fb --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/goods/service/GoodsService.java @@ -0,0 +1,211 @@ +package net.lab1024.sa.admin.module.business.goods.service; + +import cn.idev.excel.FastExcel; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.module.business.category.constant.CategoryTypeEnum; +import net.lab1024.sa.admin.module.business.category.domain.entity.CategoryEntity; +import net.lab1024.sa.admin.module.business.category.service.CategoryQueryService; +import net.lab1024.sa.admin.module.business.goods.constant.GoodsStatusEnum; +import net.lab1024.sa.admin.module.business.goods.dao.GoodsDao; +import net.lab1024.sa.admin.module.business.goods.domain.entity.GoodsEntity; +import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsAddForm; +import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsImportForm; +import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsQueryForm; +import net.lab1024.sa.admin.module.business.goods.domain.form.GoodsUpdateForm; +import net.lab1024.sa.admin.module.business.goods.domain.vo.GoodsExcelVO; +import net.lab1024.sa.admin.module.business.goods.domain.vo.GoodsVO; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartEnumUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerTypeEnum; +import net.lab1024.sa.base.module.support.datatracer.service.DataTracerService; +import net.lab1024.sa.base.module.support.dict.service.DictService; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 商品 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-10-25 20:26:54 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +@Slf4j +public class GoodsService { + + @Resource + private GoodsDao goodsDao; + + @Resource + private CategoryQueryService categoryQueryService; + + @Resource + private DataTracerService dataTracerService; + + @Resource + private DictService dictService; + + /** + * 添加商品 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO add(GoodsAddForm addForm) { + // 商品校验 + ResponseDTO res = this.checkGoods(addForm); + if (!res.getOk()) { + return res; + } + GoodsEntity goodsEntity = SmartBeanUtil.copy(addForm, GoodsEntity.class); + goodsEntity.setDeletedFlag(Boolean.FALSE); + goodsDao.insert(goodsEntity); + dataTracerService.insert(goodsEntity.getGoodsId(), DataTracerTypeEnum.GOODS); + return ResponseDTO.ok(); + } + + /** + * 更新商品 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(GoodsUpdateForm updateForm) { + // 商品校验 + ResponseDTO res = this.checkGoods(updateForm); + if (!res.getOk()) { + return res; + } + GoodsEntity originEntity = goodsDao.selectById(updateForm.getGoodsId()); + GoodsEntity goodsEntity = SmartBeanUtil.copy(updateForm, GoodsEntity.class); + goodsDao.updateById(goodsEntity); + dataTracerService.update(updateForm.getGoodsId(), DataTracerTypeEnum.GOODS, originEntity, goodsEntity); + return ResponseDTO.ok(); + } + + /** + * 添加/更新 商品校验 + */ + private ResponseDTO checkGoods(GoodsAddForm addForm) { + // 校验类目id + Long categoryId = addForm.getCategoryId(); + Optional optional = categoryQueryService.queryCategory(categoryId); + if (!optional.isPresent() || !CategoryTypeEnum.GOODS.equalsValue(optional.get().getCategoryType())) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST, "商品类目不存在~"); + } + + return ResponseDTO.ok(); + } + + /** + * 删除 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long goodsId) { + GoodsEntity goodsEntity = goodsDao.selectById(goodsId); + if (goodsEntity == null) { + return ResponseDTO.userErrorParam("商品不存在"); + } + + if (!goodsEntity.getGoodsStatus().equals(GoodsStatusEnum.SELL_OUT.getValue())) { + return ResponseDTO.userErrorParam("只有售罄的商品才可以删除"); + } + + batchDelete(Collections.singletonList(goodsId)); + dataTracerService.batchDelete(Collections.singletonList(goodsId), DataTracerTypeEnum.GOODS); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + */ + public ResponseDTO batchDelete(List goodsIdList) { + if (CollectionUtils.isEmpty(goodsIdList)) { + return ResponseDTO.ok(); + } + + goodsDao.batchUpdateDeleted(goodsIdList, Boolean.TRUE); + return ResponseDTO.ok(); + } + + + /** + * 分页查询 + */ + public ResponseDTO> query(GoodsQueryForm queryForm) { + queryForm.setDeletedFlag(false); + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = goodsDao.query(page, queryForm); + PageResult pageResult = SmartPageUtil.convert2PageResult(page, list); + if (pageResult.getEmptyFlag()) { + return ResponseDTO.ok(pageResult); + } + // 查询分类名称 + List categoryIdList = list.stream().map(GoodsVO::getCategoryId).distinct().collect(Collectors.toList()); + Map categoryMap = categoryQueryService.queryCategoryList(categoryIdList); + list.forEach(e -> { + CategoryEntity categoryEntity = categoryMap.get(e.getCategoryId()); + if (categoryEntity != null) { + e.setCategoryName(categoryEntity.getCategoryName()); + } + }); + return ResponseDTO.ok(pageResult); + } + + /** + * 商品导入 + * + * @param file 上传文件 + * @return 结果 + */ + public ResponseDTO importGoods(MultipartFile file) { + List dataList; + try { + dataList = FastExcel.read(file.getInputStream()).head(GoodsImportForm.class) + .sheet() + .doReadSync(); + } catch (IOException e) { + log.error(e.getMessage(), e); + throw new BusinessException("数据格式存在问题,无法读取"); + } + + if (CollectionUtils.isEmpty(dataList)) { + return ResponseDTO.userErrorParam("数据为空"); + } + + return ResponseDTO.okMsg("成功导入" + dataList.size() + "条,具体数据为:" + JSON.toJSONString(dataList)); + } + + /** + * 商品导出 + */ + public List getAllGoods() { + List goodsEntityList = goodsDao.selectList(null); + String dictCode = "GOODS_PLACE"; + return goodsEntityList.stream() + .map(e -> + GoodsExcelVO.builder() + .goodsStatus(SmartEnumUtil.getEnumDescByValue(e.getGoodsStatus(), GoodsStatusEnum.class)) + .categoryName(categoryQueryService.queryCategoryName(e.getCategoryId())) + .place(Arrays.stream(e.getPlace().split(",")).map(code -> dictService.getDictDataLabel(dictCode, code)).collect(Collectors.joining(","))) + .price(e.getPrice()) + .goodsName(e.getGoodsName()) + .remark(e.getRemark()) + .build() + ) + .collect(Collectors.toList()); + + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/controller/BankController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/controller/BankController.java new file mode 100644 index 0000000..7321643 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/controller/BankController.java @@ -0,0 +1,82 @@ +package net.lab1024.sa.admin.module.business.oa.bank.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.business.oa.bank.service.BankService; +import net.lab1024.sa.admin.module.business.oa.bank.domain.BankCreateForm; +import net.lab1024.sa.admin.module.business.oa.bank.domain.BankQueryForm; +import net.lab1024.sa.admin.module.business.oa.bank.domain.BankUpdateForm; +import net.lab1024.sa.admin.module.business.oa.bank.domain.BankVO; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * OA办公-OA银行信息 + * + * @Author 1024创新实验室:善逸 + * @Date 2022/6/23 21:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.Business.OA_BANK) +public class BankController { + + @Resource + private BankService bankService; + + @Operation(summary = "分页查询银行信息 @author 善逸") + @PostMapping("/oa/bank/page/query") + @SaCheckPermission("oa:bank:query") + public ResponseDTO> queryByPage(@RequestBody @Valid BankQueryForm queryForm) { + return bankService.queryByPage(queryForm); + } + + @Operation(summary = "根据企业ID查询银行信息列表 @author 善逸") + @GetMapping("/oa/bank/query/list/{enterpriseId}") + @SaCheckPermission("oa:bank:query") + public ResponseDTO> queryList(@PathVariable Long enterpriseId) { + return bankService.queryList(enterpriseId); + } + + @Operation(summary = "查询银行信息详情 @author 善逸") + @GetMapping("/oa/bank/get/{bankId}") + @SaCheckPermission("oa:bank:query") + public ResponseDTO getDetail(@PathVariable Long bankId) { + return bankService.getDetail(bankId); + } + + @Operation(summary = "新建银行信息 @author 善逸") + @PostMapping("/oa/bank/create") + @SaCheckPermission("oa:bank:add") + public ResponseDTO createBank(@RequestBody @Valid BankCreateForm createVO) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + createVO.setCreateUserId(requestUser.getUserId()); + createVO.setCreateUserName(requestUser.getUserName()); + return bankService.createBank(createVO); + } + + @Operation(summary = "编辑银行信息 @author 善逸") + @PostMapping("/oa/bank/update") + @SaCheckPermission("oa:bank:update") + public ResponseDTO updateBank(@RequestBody @Valid BankUpdateForm updateVO) { + return bankService.updateBank(updateVO); + } + + @Operation(summary = "删除银行信息 @author 善逸") + @GetMapping("/oa/bank/delete/{bankId}") + @SaCheckPermission("oa:bank:delete") + public ResponseDTO deleteBank(@PathVariable Long bankId) { + return bankService.deleteBank(bankId); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/dao/BankDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/dao/BankDao.java new file mode 100644 index 0000000..0a058d1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/dao/BankDao.java @@ -0,0 +1,46 @@ +package net.lab1024.sa.admin.module.business.oa.bank.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.business.oa.bank.domain.BankEntity; +import net.lab1024.sa.admin.module.business.oa.bank.domain.BankQueryForm; +import net.lab1024.sa.admin.module.business.oa.bank.domain.BankVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * OA办公-OA银行信息 + * + * @Author 1024创新实验室:善逸 + * @Date 2022/6/23 21:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface BankDao extends BaseMapper { + + /** + * 根据账号查询 + */ + BankEntity queryByAccountNumber(@Param("enterpriseId") Long enterpriseId, @Param("accountNumber") String accountNumber, @Param("excludeBankId") Long excludeBankId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 删除银行信息 + * + */ + void deleteBank(@Param("bankId") Long bankId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 银行信息分页查询 + * + */ + List queryPage(Page page, @Param("queryForm") BankQueryForm queryForm); + + /** + * 查询银行信息详情 + */ + BankVO getDetail(@Param("bankId") Long bankId, @Param("deletedFlag") Boolean deletedFlag); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankCreateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankCreateForm.java new file mode 100644 index 0000000..5398085 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankCreateForm.java @@ -0,0 +1,57 @@ +package net.lab1024.sa.admin.module.business.oa.bank.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +/** + * OA办公-银行信息新建 + * + * @Author 1024创新实验室:善逸 + * @Date 2022/6/23 21:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class BankCreateForm { + + @Schema(description = "开户银行") + @NotBlank(message = "开户银行不能为空") + @Length(max = 200, message = "开户银行最多200字符") + private String bankName; + + @Schema(description = "账户名称") + @NotBlank(message = "账户名称不能为空") + @Length(max = 200, message = "账户名称最多200字符") + private String accountName; + + @Schema(description = "账号") + @NotBlank(message = "账号不能为空") + @Length(max = 200, message = "账号最多200字符") + private String accountNumber; + + @Schema(description = "备注") + @Length(max = 500, message = "备注最多500字符") + private String remark; + + @Schema(description = "是否对公") + @NotNull(message = "是否对公不能为空") + private Boolean businessFlag; + + @Schema(description = "企业") + @NotNull(message = "企业不能为空") + private Long enterpriseId; + + @Schema(description = "禁用状态") + @NotNull(message = "禁用状态不能为空") + private Boolean disabledFlag; + + @Schema(hidden = true) + private Long createUserId; + + @Schema(hidden = true) + private String createUserName; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankEntity.java new file mode 100644 index 0000000..a9f0a06 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankEntity.java @@ -0,0 +1,95 @@ +package net.lab1024.sa.admin.module.business.oa.bank.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import net.lab1024.sa.base.module.support.datatracer.annoation.DataTracerFieldLabel; + +import java.time.LocalDateTime; + +/** + * OA办公-OA银行信息 + * + * @Author 1024创新实验室:善逸 + * @Date 2022/6/23 21:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_oa_bank") +public class BankEntity { + + /** + * 银行信息ID + */ + @TableId(type = IdType.AUTO) + @DataTracerFieldLabel("银行信息ID") + private Long bankId; + + /** + * 开户银行 + */ + @DataTracerFieldLabel("开户银行") + private String bankName; + + /** + * 账户名称 + */ + @DataTracerFieldLabel("账户名称") + private String accountName; + + /** + * 账号 + */ + @DataTracerFieldLabel("账号") + private String accountNumber; + + /** + * 备注 + */ + @DataTracerFieldLabel("备注") + private String remark; + + /** + * 是否对公 + */ + @DataTracerFieldLabel("是否对公") + private Boolean businessFlag; + + /** + * 企业ID + */ + private Long enterpriseId; + + /** + * 禁用状态 + */ + @DataTracerFieldLabel("禁用状态") + private Boolean disabledFlag; + + /** + * 删除状态 + */ + private Boolean deletedFlag; + + /** + * 创建人ID + */ + private Long createUserId; + + /** + * 创建人ID + */ + private String createUserName; + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankQueryForm.java new file mode 100644 index 0000000..53a405c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankQueryForm.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.oa.bank.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; +import org.hibernate.validator.constraints.Length; + +import java.time.LocalDate; + +/** + * OA办公-OA银行信息查询 + * + * @Author 1024创新实验室:善逸 + * @Date 2022/6/23 21:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class BankQueryForm extends PageParam { + + @Schema(description = "企业ID") + private Long enterpriseId; + + @Schema(description = "关键字") + @Length(max = 200, message = "关键字最多200字符") + private String keywords; + + @Schema(description = "开始时间") + private LocalDate startTime; + + @Schema(description = "结束时间") + private LocalDate endTime; + + @Schema(description = "禁用状态") + private Boolean disabledFlag; + + @Schema(description = "删除状态", hidden = true) + private Boolean deletedFlag; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankUpdateForm.java new file mode 100644 index 0000000..e77d827 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankUpdateForm.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.business.oa.bank.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * OA办公-银行信息更新 + * + * @Author 1024创新实验室:善逸 + * @Date 2022/6/23 21:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class BankUpdateForm extends BankCreateForm { + + @Schema(description = "银行信息ID") + @NotNull(message = "银行信息ID不能为空") + private Long bankId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankVO.java new file mode 100644 index 0000000..d263f38 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/domain/BankVO.java @@ -0,0 +1,58 @@ +package net.lab1024.sa.admin.module.business.oa.bank.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * OA办公-OA银行信息 + * + * @Author 1024创新实验室:善逸 + * @Date 2022/6/23 21:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class BankVO { + + @Schema(description = "银行信息ID") + private Long bankId; + + @Schema(description = "开户银行") + private String bankName; + + @Schema(description = "账户名称") + private String accountName; + + @Schema(description = "账号") + private String accountNumber; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "是否对公") + private Boolean businessFlag; + + @Schema(description = "企业ID") + private Long enterpriseId; + + @Schema(description = "企业名称") + private String enterpriseName; + + @Schema(description = "禁用状态") + private Boolean disabledFlag; + + @Schema(description = "创建人ID") + private Long createUserId; + + @Schema(description = "创建人名称") + private String createUserName; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/service/BankService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/service/BankService.java new file mode 100644 index 0000000..5b32bf6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/bank/service/BankService.java @@ -0,0 +1,146 @@ +package net.lab1024.sa.admin.module.business.oa.bank.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.module.business.oa.bank.dao.BankDao; +import net.lab1024.sa.admin.module.business.oa.bank.domain.*; +import net.lab1024.sa.admin.module.business.oa.enterprise.dao.EnterpriseDao; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEntity; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerConst; +import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerTypeEnum; +import net.lab1024.sa.base.module.support.datatracer.service.DataTracerService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; + +/** + * OA办公-OA银行信息 + * + * @Author 1024创新实验室:善逸 + * @Date 2022/6/23 21:59:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +@Slf4j +public class BankService { + + @Resource + private BankDao bankDao; + + @Resource + private EnterpriseDao enterpriseDao; + + @Resource + private DataTracerService dataTracerService; + + /** + * 分页查询银行信息 + */ + public ResponseDTO> queryByPage(BankQueryForm queryForm) { + queryForm.setDeletedFlag(Boolean.FALSE); + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List bankList = bankDao.queryPage(page, queryForm); + PageResult pageResult = SmartPageUtil.convert2PageResult(page, bankList); + return ResponseDTO.ok(pageResult); + } + + /** + * 根据企业ID查询不分页的银行列表 + */ + public ResponseDTO> queryList(Long enterpriseId) { + BankQueryForm queryForm = new BankQueryForm(); + queryForm.setEnterpriseId(enterpriseId); + queryForm.setDeletedFlag(Boolean.FALSE); + List bankList = bankDao.queryPage(null, queryForm); + return ResponseDTO.ok(bankList); + } + + /** + * 查询银行信息详情 + */ + public ResponseDTO getDetail(Long bankId) { + // 校验银行信息是否存在 + BankVO bankVO = bankDao.getDetail(bankId, Boolean.FALSE); + if (Objects.isNull(bankVO)) { + return ResponseDTO.userErrorParam("银行信息不存在"); + } + return ResponseDTO.ok(bankVO); + } + + /** + * 新建银行信息 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO createBank(BankCreateForm createVO) { + Long enterpriseId = createVO.getEnterpriseId(); + // 校验企业是否存在 + EnterpriseEntity enterpriseDetail = enterpriseDao.selectById(enterpriseId); + if (Objects.isNull(enterpriseDetail) || enterpriseDetail.getDeletedFlag()) { + return ResponseDTO.userErrorParam("企业不存在"); + } + // 验证银行信息账号是否重复 + BankEntity validateBank = bankDao.queryByAccountNumber(enterpriseId, createVO.getAccountNumber(), null, Boolean.FALSE); + if (Objects.nonNull(validateBank)) { + return ResponseDTO.userErrorParam("银行信息账号重复"); + } + // 数据插入 + BankEntity insertBank = SmartBeanUtil.copy(createVO, BankEntity.class); + bankDao.insert(insertBank); + dataTracerService.addTrace(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE, "新增银行:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(insertBank)); + return ResponseDTO.ok(); + } + + /** + * 编辑银行信息 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO updateBank(BankUpdateForm updateVO) { + Long enterpriseId = updateVO.getEnterpriseId(); + // 校验企业是否存在 + EnterpriseEntity enterpriseDetail = enterpriseDao.selectById(enterpriseId); + if (Objects.isNull(enterpriseDetail) || enterpriseDetail.getDeletedFlag()) { + return ResponseDTO.userErrorParam("企业不存在"); + } + Long bankId = updateVO.getBankId(); + // 校验银行信息是否存在 + BankEntity bankDetail = bankDao.selectById(bankId); + if (Objects.isNull(bankDetail) || bankDetail.getDeletedFlag()) { + return ResponseDTO.userErrorParam("银行信息不存在"); + } + // 验证银行信息账号是否重复 + BankEntity validateBank = bankDao.queryByAccountNumber(updateVO.getEnterpriseId(), updateVO.getAccountNumber(), bankId, Boolean.FALSE); + if (Objects.nonNull(validateBank)) { + return ResponseDTO.userErrorParam("银行信息账号重复"); + } + // 数据编辑 + BankEntity updateBank = SmartBeanUtil.copy(updateVO, BankEntity.class); + bankDao.updateById(updateBank); + dataTracerService.addTrace(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE, "更新银行:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(bankDetail, updateBank)); + return ResponseDTO.ok(); + } + + + /** + * 删除银行信息 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO deleteBank(Long bankId) { + // 校验银行信息是否存在 + BankEntity bankDetail = bankDao.selectById(bankId); + if (Objects.isNull(bankDetail) || bankDetail.getDeletedFlag()) { + return ResponseDTO.userErrorParam("银行信息不存在"); + } + bankDao.deleteBank(bankId, Boolean.TRUE); + dataTracerService.addTrace(bankDetail.getEnterpriseId(), DataTracerTypeEnum.OA_ENTERPRISE, "删除银行:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(bankDetail)); + return ResponseDTO.ok(); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/constant/EnterpriseTypeEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/constant/EnterpriseTypeEnum.java new file mode 100644 index 0000000..9603355 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/constant/EnterpriseTypeEnum.java @@ -0,0 +1,46 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.constant; + + +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 企业类型 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public enum EnterpriseTypeEnum implements BaseEnum { + + /** + * 有限企业 + */ + NORMAL(1, "有限企业"), + + /** + * 外资企业 + */ + FOREIGN(2, "外资企业"), + ; + + private Integer value; + private String desc; + + EnterpriseTypeEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + + @Override + public Integer getValue() { + return value; + } + + @Override + public String getDesc() { + return desc; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/controller/EnterpriseController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/controller/EnterpriseController.java new file mode 100644 index 0000000..ab06bd0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/controller/EnterpriseController.java @@ -0,0 +1,138 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.business.oa.enterprise.service.EnterpriseService; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.form.*; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO; +import net.lab1024.sa.admin.util.AdminRequestUtil; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.*; +import net.lab1024.sa.base.module.support.operatelog.annotation.OperateLog; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 企业 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Slf4j +@RestController +@Tag(name = AdminSwaggerTagConst.Business.OA_ENTERPRISE) +@OperateLog +public class EnterpriseController { + + @Resource + private EnterpriseService enterpriseService; + + @Operation(summary = "分页查询企业模块 @author 开云") + @PostMapping("/oa/enterprise/page/query") + @SaCheckPermission("oa:enterprise:query") + public ResponseDTO> queryByPage(@RequestBody @Valid EnterpriseQueryForm queryForm) { + return enterpriseService.queryByPage(queryForm); + } + + @Operation(summary = "导出企业信息 @author 卓大") + @PostMapping("/oa/enterprise/exportExcel") + public void exportExcel(@RequestBody @Valid EnterpriseQueryForm queryForm, HttpServletResponse response) throws IOException { + List data = enterpriseService.getExcelExportData(queryForm); + if (CollectionUtils.isEmpty(data)) { + SmartResponseUtil.write(response, ResponseDTO.userErrorParam("暂无数据")); + return; + } + + String watermark = AdminRequestUtil.getRequestUser().getActualName(); + watermark += SmartLocalDateUtil.format(LocalDateTime.now(), SmartDateFormatterEnum.YMD_HMS); + + SmartExcelUtil.exportExcelWithWatermark(response,"企业基本信息.xlsx","企业信息",EnterpriseExcelVO.class,data,watermark); + + } + + @Operation(summary = "查询企业详情 @author 开云") + @GetMapping("/oa/enterprise/get/{enterpriseId}") + @SaCheckPermission("oa:enterprise:detail") + public ResponseDTO getDetail(@PathVariable Long enterpriseId) { + return ResponseDTO.ok(enterpriseService.getDetail(enterpriseId)); + } + + @Operation(summary = "新建企业 @author 开云") + @PostMapping("/oa/enterprise/create") + @SaCheckPermission("oa:enterprise:add") + public ResponseDTO createEnterprise(@RequestBody @Valid EnterpriseCreateForm createVO) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + createVO.setCreateUserId(requestUser.getUserId()); + createVO.setCreateUserName(requestUser.getUserName()); + return enterpriseService.createEnterprise(createVO); + } + + @Operation(summary = "编辑企业 @author 开云") + @PostMapping("/oa/enterprise/update") + @SaCheckPermission("oa:enterprise:update") + public ResponseDTO updateEnterprise(@RequestBody @Valid EnterpriseUpdateForm updateVO) { + return enterpriseService.updateEnterprise(updateVO); + } + + @Operation(summary = "删除企业 @author 开云") + @GetMapping("/oa/enterprise/delete/{enterpriseId}") + @SaCheckPermission("oa:enterprise:delete") + public ResponseDTO deleteEnterprise(@PathVariable Long enterpriseId) { + return enterpriseService.deleteEnterprise(enterpriseId); + } + + @Operation(summary = "按照类型查询企业 @author 开云") + @GetMapping("/oa/enterprise/query/list") + @SaCheckPermission("oa:enterprise:query") + public ResponseDTO> queryList(@RequestParam(value = "type", required = false) Integer type) { + return enterpriseService.queryList(type); + } + + + @Operation(summary = "企业添加员工 @author 罗伊") + @PostMapping("/oa/enterprise/employee/add") + @SaCheckPermission("oa:enterprise:addEmployee") + public ResponseDTO addEmployee(@RequestBody @Valid EnterpriseEmployeeForm enterpriseEmployeeForm) { + return enterpriseService.addEmployee(enterpriseEmployeeForm); + } + + @Operation(summary = "查询企业全部员工 @author 罗伊") + @PostMapping("/oa/enterprise/employee/list") + @SaCheckPermission("oa:enterprise:queryEmployee") + public ResponseDTO> employeeList(@RequestBody @Valid List enterpriseIdList) { + return ResponseDTO.ok(enterpriseService.employeeList(enterpriseIdList)); + } + + @Operation(summary = "分页查询企业员工 @author 卓大") + @PostMapping("/oa/enterprise/employee/queryPage") + @SaCheckPermission("oa:enterprise:queryEmployee") + public ResponseDTO> queryPageEmployeeList(@RequestBody @Valid EnterpriseEmployeeQueryForm queryForm) { + return ResponseDTO.ok(enterpriseService.queryPageEmployeeList(queryForm)); + } + + + @Operation(summary = "企业删除员工 @author 罗伊") + @PostMapping("/oa/enterprise/employee/delete") + @SaCheckPermission("oa:enterprise:deleteEmployee") + public ResponseDTO deleteEmployee(@RequestBody @Valid EnterpriseEmployeeForm enterpriseEmployeeForm) { + return enterpriseService.deleteEmployee(enterpriseEmployeeForm); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/dao/EnterpriseDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/dao/EnterpriseDao.java new file mode 100644 index 0000000..bde9499 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/dao/EnterpriseDao.java @@ -0,0 +1,64 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEntity; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.form.EnterpriseQueryForm; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 企业 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface EnterpriseDao extends BaseMapper { + + /** + * 根据企业名称查询 + * + */ + EnterpriseEntity queryByEnterpriseName(@Param("enterpriseName") String enterpriseName, @Param("excludeEnterpriseId") Long excludeEnterpriseId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 删除企业 + */ + void deleteEnterprise(@Param("enterpriseId") Long enterpriseId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 企业分页查询 + * + */ + List queryPage(Page page, @Param("queryForm") EnterpriseQueryForm queryForm); + + /** + * 查询导出的数据 + * + */ + List selectExcelExportData(@Param("queryForm") EnterpriseQueryForm queryForm); + + /** + * 查询企业详情 + * + */ + EnterpriseVO getDetail(@Param("enterpriseId") Long enterpriseId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 查询列表 + * + */ + List queryList(@Param("type") Integer type, @Param("disabledFlag") Boolean disabledFlag, @Param("deletedFlag") Boolean deletedFlag); + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/dao/EnterpriseEmployeeDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/dao/EnterpriseEmployeeDao.java new file mode 100644 index 0000000..e73a493 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/dao/EnterpriseEmployeeDao.java @@ -0,0 +1,69 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEmployeeEntity; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.form.EnterpriseEmployeeQueryForm; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; + +/** + * 企业员工 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface EnterpriseEmployeeDao extends BaseMapper { + + + /** + * 根据员工查询 + */ + List selectByEmployeeIdList(@Param("employeeIdList")Collection employeeIdList); + + /** + * 查询员工关联的企业 + */ + List selectEnterpriseIdByEmployeeId(@Param("employeeId")Long employeeId); + /** + * 根据企业查询 + */ + List selectByEnterpriseIdList(@Param("enterpriseIdList")Collection enterpriseIdList); + /** + * 根据企业查询 + */ + List selectByEnterpriseId(@Param("enterpriseId")Long enterpriseId); + + /** + * 查询企业下的所有员工id + */ + List selectEmployeeIdByEnterpriseIdList(@Param("enterpriseIdList")Collection enterpriseIdList); + /** + * 根据员工删除 + */ + void deleteByEnterpriseAndEmployeeIdList(@Param("enterpriseId")Long enterpriseId, @Param("employeeIdList")Collection employeeIdList); + + /** + * 根据员工查询 + */ + List selectByEnterpriseAndEmployeeIdList(@Param("enterpriseId")Long enterpriseId, @Param("employeeIdList")Collection employeeIdList); + + /** + * 删除某员工关联的所有企业 + */ + void deleteByEmployeeId(@Param("employeeId")Long employeeId); + + /** + * 分页查询企业员工 + */ + List queryPageEmployeeList(Page page,@Param("queryForm") EnterpriseEmployeeQueryForm queryForm); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEmployeeEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEmployeeEntity.java new file mode 100644 index 0000000..9f458fc --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEmployeeEntity.java @@ -0,0 +1,51 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 企业员工 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_oa_enterprise_employee") +@NoArgsConstructor +public class EnterpriseEmployeeEntity { + + @TableId(type = IdType.AUTO) + private Long enterpriseEmployeeId; + + /** + * 企业ID + */ + private Long enterpriseId; + /** + * 员工 + */ + private Long employeeId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + public EnterpriseEmployeeEntity(Long enterpriseId, Long employeeId) { + this.enterpriseId = enterpriseId; + this.employeeId = employeeId; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEntity.java new file mode 100644 index 0000000..549c9be --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/entity/EnterpriseEntity.java @@ -0,0 +1,153 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import net.lab1024.sa.admin.module.business.oa.enterprise.constant.EnterpriseTypeEnum; +import net.lab1024.sa.base.module.support.datatracer.annoation.DataTracerFieldEnum; +import net.lab1024.sa.base.module.support.datatracer.annoation.DataTracerFieldLabel; + +import java.time.LocalDateTime; + +/** + * 企业 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_oa_enterprise") +public class EnterpriseEntity { + + /** + * 企业ID + */ + @TableId(type = IdType.AUTO) + private Long enterpriseId; + + /** + * 企业名称 + */ + @DataTracerFieldLabel("企业名称") + private String enterpriseName; + + /** + * 企业logo + */ + @DataTracerFieldLabel("企业logo") + private String enterpriseLogo; + + /** + * 统一社会信用代码 + */ + @DataTracerFieldLabel("统一社会信用代码") + private String unifiedSocialCreditCode; + + /** + * 类型 + * + * @see EnterpriseTypeEnum + */ + @DataTracerFieldLabel("类型") + @DataTracerFieldEnum(enumClass = EnterpriseTypeEnum.class) + private Integer type; + + /** + * 联系人 + */ + @DataTracerFieldLabel("联系人") + private String contact; + + /** + * 联系人电话 + */ + @DataTracerFieldLabel("联系人电话") + private String contactPhone; + + /** + * 邮箱 + */ + @DataTracerFieldLabel("邮箱") + private String email; + + /** + * 省份 + */ + private Integer province; + + /** + * 省份名称 + */ + @DataTracerFieldLabel("省份名称") + private String provinceName; + + /** + * 城市 + */ + private Integer city; + + /** + * 城市名称 + */ + @DataTracerFieldLabel("城市名称") + private String cityName; + + /** + * 区县 + */ + private Integer district; + + /** + * 区县名称 + */ + @DataTracerFieldLabel("区县名称") + private String districtName; + + /** + * 详细地址 + */ + @DataTracerFieldLabel("详细地址") + private String address; + + /** + * 营业执照 + */ + @DataTracerFieldLabel("营业执照") + private String businessLicense; + + /** + * 禁用状态 + */ + @DataTracerFieldLabel("禁用状态") + private Boolean disabledFlag; + + /** + * 删除状态 + */ + @DataTracerFieldLabel("删除状态") + private Boolean deletedFlag; + + /** + * 创建人ID + */ + private Long createUserId; + + /** + * 创建人ID + */ + private String createUserName; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseCreateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseCreateForm.java new file mode 100644 index 0000000..02ff750 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseCreateForm.java @@ -0,0 +1,100 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.form; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import net.lab1024.sa.admin.module.business.oa.enterprise.constant.EnterpriseTypeEnum; +import net.lab1024.sa.base.common.json.deserializer.FileKeyVoDeserializer; +import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.util.SmartVerificationUtil; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import org.hibernate.validator.constraints.Length; + +/** + * OA企业模块创建 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EnterpriseCreateForm { + + @Schema(description = "企业名称") + @NotBlank(message = "企业名称不能为空") + @Length(max = 200, message = "企业名称最多200字符") + private String enterpriseName; + + @Schema(description = "企业logo") + @JsonSerialize(using = FileKeyVoSerializer.class) + @JsonDeserialize(using = FileKeyVoDeserializer.class) + private String enterpriseLogo; + + @Schema(description = "统一社会信用代码") + @NotBlank(message = "统一社会信用代码不能为空") + @Length(max = 200, message = "统一社会信用代码最多200字符") + private String unifiedSocialCreditCode; + + @Schema(description = "联系人") + @NotBlank(message = "联系人不能为空") + @Length(max = 100, message = "联系人最多100字符") + private String contact; + + @Schema(description = "联系人电话") + @NotBlank(message = "联系人电话不能为空") + @Pattern(regexp = SmartVerificationUtil.PHONE_REGEXP, message = "手机号格式不正确") + private String contactPhone; + + @SchemaEnum(desc = "类型", value = EnterpriseTypeEnum.class) + @CheckEnum(message = "类型不正确", value = EnterpriseTypeEnum.class) + private Integer type; + + @Schema(description = "邮箱") + @Pattern(regexp = SmartVerificationUtil.EMAIL, message = "邮箱格式不正确") + private String email; + + @Schema(description = "省份") + private Integer province; + + @Schema(description = "省份名称") + private String provinceName; + + @Schema(description = "城市") + private Integer city; + + @Schema(description = "城市名称") + private String cityName; + + @Schema(description = "区县") + private Integer district; + + @Schema(description = "区县名称") + private String districtName; + + @Schema(description = "详细地址") + @Length(max = 500, message = "详细地址最多500字符") + private String address; + + @Schema(description = "营业执照") + @JsonSerialize(using = FileKeyVoSerializer.class) + @JsonDeserialize(using = FileKeyVoDeserializer.class) + private String businessLicense; + + @Schema(description = "禁用状态") + @NotNull(message = "禁用状态不能为空") + private Boolean disabledFlag; + + @Schema(description = "创建人", hidden = true) + private Long createUserId; + + @Schema(description = "创建人", hidden = true) + private String createUserName; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeForm.java new file mode 100644 index 0000000..ce74d4e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeForm.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +/** + * 企业员工 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EnterpriseEmployeeForm { + + @Schema(description = "企业id") + @NotNull(message = "企业id不能为空") + private Long enterpriseId; + + @Schema(description = "员工信息id") + @NotEmpty(message = "员工信息id不能为空") + private List employeeIdList; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeQueryForm.java new file mode 100644 index 0000000..eba6b98 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseEmployeeQueryForm.java @@ -0,0 +1,32 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; +import org.hibernate.validator.constraints.Length; + +/** + * 查询企业员工 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-20 21:06:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EnterpriseEmployeeQueryForm extends PageParam { + + @Schema(description = "搜索词") + @Length(max = 20, message = "搜索词最多20字符") + private String keyword; + + @Schema(description = "公司Id") + @NotNull(message = "公司id 不能为空") + private Long enterpriseId; + + @Schema(description = "删除标识", hidden = true) + private Boolean deletedFlag; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseQueryForm.java new file mode 100644 index 0000000..7891508 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseQueryForm.java @@ -0,0 +1,38 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; +import org.hibernate.validator.constraints.Length; + +import java.time.LocalDate; + +/** + * OA企业模块分页查询 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EnterpriseQueryForm extends PageParam { + + @Schema(description = "关键字") + @Length(max = 200, message = "关键字最多200字符") + private String keywords; + + @Schema(description = "开始时间") + private LocalDate startTime; + + @Schema(description = "结束时间") + private LocalDate endTime; + + @Schema(description = "禁用状态") + private Boolean disabledFlag; + + @Schema(description = "删除状态", hidden = true) + private Boolean deletedFlag; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseUpdateForm.java new file mode 100644 index 0000000..f2978d2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/form/EnterpriseUpdateForm.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * OA企业模块编辑 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EnterpriseUpdateForm extends EnterpriseCreateForm { + + @Schema(description = "企业ID") + @NotNull(message = "企业ID不能为空") + private Long enterpriseId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseEmployeeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseEmployeeVO.java new file mode 100644 index 0000000..18aa205 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseEmployeeVO.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 企业员工信息 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EnterpriseEmployeeVO { + + private Long enterpriseEmployeeId; + + @Schema(description = "企业ID") + private Long enterpriseId; + + @Schema(description = "企业名称") + private String enterpriseName; + + @Schema(description = "员工") + private Long employeeId; + + @Schema(description = "登录账号") + private String loginName; + + @Schema(description = "员工名称") + private String actualName; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "部门id") + private Long departmentId; + + @Schema(description = "是否被禁用") + private Boolean disabledFlag; + + @Schema(description = "部门名称") + private String departmentName; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseExcelVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseExcelVO.java new file mode 100644 index 0000000..8b9c838 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseExcelVO.java @@ -0,0 +1,48 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo; + +import cn.idev.excel.annotation.ExcelProperty; +import lombok.Data; + +/** + * 企业信息 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EnterpriseExcelVO { + + @ExcelProperty("企业名称") + private String enterpriseName; + + @ExcelProperty("统一社会信用代码") + private String unifiedSocialCreditCode; + + @ExcelProperty("企业类型") + private String typeName; + + @ExcelProperty("联系人") + private String contact; + + @ExcelProperty("联系人电话") + private String contactPhone; + + @ExcelProperty("邮箱") + private String email; + + @ExcelProperty("省份名称") + private String provinceName; + + @ExcelProperty("城市名称") + private String cityName; + + @ExcelProperty("区县名称") + private String districtName; + + @ExcelProperty("详细地址") + private String address; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseListVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseListVO.java new file mode 100644 index 0000000..1320292 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseListVO.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * OA企业模块列表 + * + * @author lihaifan + * @date 2022/6/23 14:31 + */ +@Data +public class EnterpriseListVO { + + @Schema(description = "企业ID") + private Long enterpriseId; + + @Schema(description = "企业名称") + private String enterpriseName; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseVO.java new file mode 100644 index 0000000..54d9b47 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/domain/vo/EnterpriseVO.java @@ -0,0 +1,89 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.business.oa.enterprise.constant.EnterpriseTypeEnum; +import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer; +import net.lab1024.sa.base.common.swagger.SchemaEnum; + +import java.time.LocalDateTime; + +/** + * 企业信息 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EnterpriseVO { + + @Schema(description = "企业ID") + private Long enterpriseId; + + @Schema(description = "企业名称") + private String enterpriseName; + + @Schema(description = "企业logo") + @JsonSerialize(using = FileKeyVoSerializer.class) + private String enterpriseLogo; + + @Schema(description = "统一社会信用代码") + private String unifiedSocialCreditCode; + + @SchemaEnum(desc = "类型", value = EnterpriseTypeEnum.class) + private Integer type; + + @Schema(description = "联系人") + private String contact; + + @Schema(description = "联系人电话") + private String contactPhone; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "省份") + private Integer province; + + @Schema(description = "省份名称") + private String provinceName; + + @Schema(description = "城市") + private Integer city; + + @Schema(description = "城市名称") + private String cityName; + + @Schema(description = "区县") + private Integer district; + + @Schema(description = "区县名称") + private String districtName; + + @Schema(description = "详细地址") + private String address; + + @Schema(description = "营业执照") + @JsonSerialize(using = FileKeyVoSerializer.class) + private String businessLicense; + + @Schema(description = "禁用状态") + private Boolean disabledFlag; + + @Schema(description = "创建人ID") + private Long createUserId; + + @Schema(description = "创建人名称") + private String createUserName; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/manager/EnterpriseEmployeeManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/manager/EnterpriseEmployeeManager.java new file mode 100644 index 0000000..a3c21d8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/manager/EnterpriseEmployeeManager.java @@ -0,0 +1,19 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.manager; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.lab1024.sa.admin.module.business.oa.enterprise.dao.EnterpriseEmployeeDao; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEmployeeEntity; +import org.springframework.stereotype.Service; + +/** + * 企业员工关系 manager + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class EnterpriseEmployeeManager extends ServiceImpl { +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/service/EnterpriseService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/service/EnterpriseService.java new file mode 100644 index 0000000..3784877 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/enterprise/service/EnterpriseService.java @@ -0,0 +1,239 @@ +package net.lab1024.sa.admin.module.business.oa.enterprise.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.module.business.oa.enterprise.dao.EnterpriseDao; +import net.lab1024.sa.admin.module.business.oa.enterprise.dao.EnterpriseEmployeeDao; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEmployeeEntity; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.entity.EnterpriseEntity; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.form.*; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseEmployeeVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseExcelVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseListVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO; +import net.lab1024.sa.admin.module.business.oa.enterprise.manager.EnterpriseEmployeeManager; +import net.lab1024.sa.admin.module.system.department.service.DepartmentService; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerTypeEnum; +import net.lab1024.sa.base.module.support.datatracer.domain.form.DataTracerForm; +import net.lab1024.sa.base.module.support.datatracer.service.DataTracerService; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 企业 + * + * @Author 1024创新实验室: 开云 + * @Date 2022/7/28 20:37:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +@Slf4j +public class EnterpriseService { + + @Resource + private EnterpriseDao enterpriseDao; + + @Resource + private EnterpriseEmployeeDao enterpriseEmployeeDao; + + @Resource + private EnterpriseEmployeeManager enterpriseEmployeeManager; + + @Resource + private DataTracerService dataTracerService; + + @Resource + private DepartmentService departmentService; + + /** + * 分页查询企业模块 + * + */ + public ResponseDTO> queryByPage(EnterpriseQueryForm queryForm) { + queryForm.setDeletedFlag(Boolean.FALSE); + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List enterpriseList = enterpriseDao.queryPage(page, queryForm); + PageResult pageResult = SmartPageUtil.convert2PageResult(page, enterpriseList); + return ResponseDTO.ok(pageResult); + } + + /** + * 获取导出数据 + */ + public List getExcelExportData(EnterpriseQueryForm queryForm) { + queryForm.setDeletedFlag(false); + return enterpriseDao.selectExcelExportData(queryForm); + } + + /** + * 查询企业详情 + * + */ + public EnterpriseVO getDetail(Long enterpriseId) { + return enterpriseDao.getDetail(enterpriseId, Boolean.FALSE); + } + + /** + * 新建企业 + * + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO createEnterprise(EnterpriseCreateForm createVO) { + // 验证企业名称是否重复 + EnterpriseEntity validateEnterprise = enterpriseDao.queryByEnterpriseName(createVO.getEnterpriseName(), null, Boolean.FALSE); + if (Objects.nonNull(validateEnterprise)) { + return ResponseDTO.userErrorParam("企业名称重复"); + } + // 数据插入 + EnterpriseEntity insertEnterprise = SmartBeanUtil.copy(createVO, EnterpriseEntity.class); + enterpriseDao.insert(insertEnterprise); + dataTracerService.insert(insertEnterprise.getEnterpriseId(), DataTracerTypeEnum.OA_ENTERPRISE); + return ResponseDTO.ok(); + } + + /** + * 编辑企业 + * + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO updateEnterprise(EnterpriseUpdateForm updateVO) { + Long enterpriseId = updateVO.getEnterpriseId(); + // 校验企业是否存在 + EnterpriseEntity enterpriseDetail = enterpriseDao.selectById(enterpriseId); + if (Objects.isNull(enterpriseDetail) || enterpriseDetail.getDeletedFlag()) { + return ResponseDTO.userErrorParam("企业不存在"); + } + // 验证企业名称是否重复 + EnterpriseEntity validateEnterprise = enterpriseDao.queryByEnterpriseName(updateVO.getEnterpriseName(), enterpriseId, Boolean.FALSE); + if (Objects.nonNull(validateEnterprise)) { + return ResponseDTO.userErrorParam("企业名称重复"); + } + // 数据编辑 + EnterpriseEntity updateEntity = SmartBeanUtil.copy(enterpriseDetail, EnterpriseEntity.class); + SmartBeanUtil.copyProperties(updateVO, updateEntity); + enterpriseDao.updateById(updateEntity); + + //变更记录 + DataTracerForm dataTracerForm = DataTracerForm.builder() + .dataId(updateVO.getEnterpriseId()) + .type(DataTracerTypeEnum.OA_ENTERPRISE) + .content("修改企业信息") + .diffOld(dataTracerService.getChangeContent(enterpriseDetail)) + .diffNew(dataTracerService.getChangeContent(updateEntity)) + .build(); + + dataTracerService.addTrace(dataTracerForm); + return ResponseDTO.ok(); + } + + + /** + * 删除企业 + * + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO deleteEnterprise(Long enterpriseId) { + // 校验企业是否存在 + EnterpriseEntity enterpriseDetail = enterpriseDao.selectById(enterpriseId); + if (Objects.isNull(enterpriseDetail) || enterpriseDetail.getDeletedFlag()) { + return ResponseDTO.userErrorParam("企业不存在"); + } + enterpriseDao.deleteEnterprise(enterpriseId, Boolean.TRUE); + dataTracerService.delete(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE); + return ResponseDTO.ok(); + } + + /** + * 企业列表查询 + */ + public ResponseDTO> queryList(Integer type) { + List enterpriseList = enterpriseDao.queryList(type, Boolean.FALSE, Boolean.FALSE); + return ResponseDTO.ok(enterpriseList); + } + + //----------------------------------------- 以下为员工相关-------------------------------------------- + + /** + * 企业添加员工 + * + */ + public synchronized ResponseDTO addEmployee(EnterpriseEmployeeForm enterpriseEmployeeForm) { + Long enterpriseId = enterpriseEmployeeForm.getEnterpriseId(); + EnterpriseEntity enterpriseEntity = enterpriseDao.selectById(enterpriseId); + if (enterpriseEntity == null || enterpriseEntity.getDeletedFlag()) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + //过滤掉已存在的员工 + List waitAddEmployeeIdList = enterpriseEmployeeForm.getEmployeeIdList(); + List enterpriseEmployeeEntityList = enterpriseEmployeeDao.selectByEnterpriseAndEmployeeIdList(enterpriseId, waitAddEmployeeIdList); + if (CollectionUtils.isNotEmpty(enterpriseEmployeeEntityList)) { + List existEmployeeIdList = enterpriseEmployeeEntityList.stream().map(EnterpriseEmployeeEntity::getEmployeeId).collect(Collectors.toList()); + waitAddEmployeeIdList = waitAddEmployeeIdList.stream().filter(e -> !existEmployeeIdList.contains(e)).collect(Collectors.toList()); + } + if (CollectionUtils.isEmpty(waitAddEmployeeIdList)) { + return ResponseDTO.ok(); + } + List batchAddList = Lists.newArrayList(); + for (Long employeeId : waitAddEmployeeIdList) { + EnterpriseEmployeeEntity enterpriseEmployeeEntity = new EnterpriseEmployeeEntity(); + enterpriseEmployeeEntity.setEnterpriseId(enterpriseId); + enterpriseEmployeeEntity.setEmployeeId(employeeId); + batchAddList.add(enterpriseEmployeeEntity); + } + enterpriseEmployeeManager.saveBatch(batchAddList); + return ResponseDTO.ok(); + } + + /** + * 企业删除员工 + * + */ + public synchronized ResponseDTO deleteEmployee(EnterpriseEmployeeForm enterpriseEmployeeForm) { + Long enterpriseId = enterpriseEmployeeForm.getEnterpriseId(); + EnterpriseEntity enterpriseEntity = enterpriseDao.selectById(enterpriseId); + if (enterpriseEntity == null || enterpriseEntity.getDeletedFlag()) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + List waitDeleteEmployeeIdList = enterpriseEmployeeForm.getEmployeeIdList(); + enterpriseEmployeeDao.deleteByEnterpriseAndEmployeeIdList(enterpriseId, waitDeleteEmployeeIdList); + return ResponseDTO.ok(); + } + + /** + * 企业下员工列表 + * + */ + public List employeeList(List enterpriseIdList) { + if (CollectionUtils.isEmpty(enterpriseIdList)) { + return Lists.newArrayList(); + } + return enterpriseEmployeeDao.selectByEnterpriseIdList(enterpriseIdList); + } + + /** + * 分页查询企业员工 + * + */ + public PageResult queryPageEmployeeList(EnterpriseEmployeeQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List enterpriseEmployeeVOList = enterpriseEmployeeDao.queryPageEmployeeList(page, queryForm); + for (EnterpriseEmployeeVO enterpriseEmployeeVO : enterpriseEmployeeVOList) { + enterpriseEmployeeVO.setDepartmentName(departmentService.getDepartmentPath(enterpriseEmployeeVO.getDepartmentId())); + } + return SmartPageUtil.convert2PageResult(page, enterpriseEmployeeVOList); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/controller/InvoiceController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/controller/InvoiceController.java new file mode 100644 index 0000000..380be16 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/controller/InvoiceController.java @@ -0,0 +1,88 @@ +package net.lab1024.sa.admin.module.business.oa.invoice.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.business.oa.invoice.service.InvoiceService; +import net.lab1024.sa.admin.module.business.oa.invoice.domain.InvoiceAddForm; +import net.lab1024.sa.admin.module.business.oa.invoice.domain.InvoiceQueryForm; +import net.lab1024.sa.admin.module.business.oa.invoice.domain.InvoiceUpdateForm; +import net.lab1024.sa.admin.module.business.oa.invoice.domain.InvoiceVO; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.module.support.operatelog.annotation.OperateLog; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * OA发票信息 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-06-23 19:32:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Slf4j +@RestController +@Tag(name = AdminSwaggerTagConst.Business.OA_INVOICE) +public class InvoiceController { + + @Resource + private InvoiceService invoiceService; + + @Operation(summary = "分页查询发票信息 @author 善逸") + @PostMapping("/oa/invoice/page/query") + @SaCheckPermission("oa:invoice:query") + public ResponseDTO> queryByPage(@RequestBody @Valid InvoiceQueryForm queryForm) { + return invoiceService.queryByPage(queryForm); + } + + @Operation(summary = "查询发票信息详情 @author 善逸") + @GetMapping("/oa/invoice/get/{invoiceId}") + @SaCheckPermission("oa:invoice:query") + public ResponseDTO getDetail(@PathVariable Long invoiceId) { + return invoiceService.getDetail(invoiceId); + } + + @Operation(summary = "新建发票信息 @author 善逸") + @PostMapping("/oa/invoice/create") + @SaCheckPermission("oa:invoice:add") + public ResponseDTO createInvoice(@RequestBody @Valid InvoiceAddForm createVO) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + createVO.setCreateUserId(requestUser.getUserId()); + createVO.setCreateUserName(requestUser.getUserName()); + return invoiceService.createInvoice(createVO); + } + + @OperateLog + @Operation(summary = "编辑发票信息 @author 善逸") + @PostMapping("/oa/invoice/update") + @SaCheckPermission("oa:invoice:update") + public ResponseDTO updateInvoice(@RequestBody @Valid InvoiceUpdateForm updateVO) { + return invoiceService.updateInvoice(updateVO); + } + + @Operation(summary = "删除发票信息 @author 善逸") + @GetMapping("/invoice/delete/{invoiceId}") + @SaCheckPermission("oa:invoice:delete") + public ResponseDTO deleteInvoice(@PathVariable Long invoiceId) { + return invoiceService.deleteInvoice(invoiceId); + } + + @Operation(summary = "查询列表 @author lidoudou") + @GetMapping("/oa/invoice/query/list/{enterpriseId}") + @SaCheckPermission("oa:invoice:query") + public ResponseDTO> queryList(@PathVariable Long enterpriseId) { + return invoiceService.queryList(enterpriseId); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/dao/InvoiceDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/dao/InvoiceDao.java new file mode 100644 index 0000000..5afcebb --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/dao/InvoiceDao.java @@ -0,0 +1,59 @@ +package net.lab1024.sa.admin.module.business.oa.invoice.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.business.oa.invoice.domain.InvoiceEntity; +import net.lab1024.sa.admin.module.business.oa.invoice.domain.InvoiceQueryForm; +import net.lab1024.sa.admin.module.business.oa.invoice.domain.InvoiceVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * OA发票信息 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-06-23 19:32:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface InvoiceDao extends BaseMapper { + + /** + * 根据账号查询 + * @param enterpriseId + * @param accountNumber + * @param excludeInvoiceId + * @param deletedFlag + * @return + */ + InvoiceEntity queryByAccountNumber(@Param("enterpriseId") Long enterpriseId, @Param("accountNumber") String accountNumber, @Param("excludeInvoiceId") Long excludeInvoiceId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 删除发票信息 + * + * @param invoiceId + * @param deletedFlag + */ + void deleteInvoice(@Param("invoiceId") Long invoiceId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 发票信息分页查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") InvoiceQueryForm queryForm); + + /** + * 查询发票信息详情 + * @param invoiceId + * @param deletedFlag + * @return + */ + InvoiceVO getDetail(@Param("invoiceId") Long invoiceId, @Param("deletedFlag") Boolean deletedFlag); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceAddForm.java new file mode 100644 index 0000000..136178a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceAddForm.java @@ -0,0 +1,58 @@ +package net.lab1024.sa.admin.module.business.oa.invoice.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +/** + * OA发票信息新建 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-06-23 19:32:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class InvoiceAddForm { + + @Schema(description = "开票抬头") + @NotBlank(message = "开票抬头不能为空") + @Length(max = 200, message = "开票抬头最多200字符") + private String invoiceHeads; + + @Schema(description = "纳税人识别号") + @NotBlank(message = "纳税人识别号不能为空") + @Length(max = 200, message = "纳税人识别号最多200字符") + private String taxpayerIdentificationNumber; + + @Schema(description = "银行账户") + @NotBlank(message = "银行账户不能为空") + @Length(max = 200, message = "银行账户最多200字符") + private String accountNumber; + + @Schema(description = "开户行") + @NotBlank(message = "开户行不能为空") + @Length(max = 200, message = "开户行最多200字符") + private String bankName; + + @Schema(description = "启用状态") + @NotNull(message = "启用状态不能为空") + private Boolean disabledFlag; + + @Schema(description = "备注") + @Length(max = 500, message = "备注最多500字符") + private String remark; + + @Schema(description = "企业") + @NotNull(message = "企业不能为空") + private Long enterpriseId; + + @Schema(description = "创建人", hidden = true) + private Long createUserId; + + @Schema(description = "创建人名称", hidden = true) + private String createUserName; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceEntity.java new file mode 100644 index 0000000..a297f03 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceEntity.java @@ -0,0 +1,98 @@ +package net.lab1024.sa.admin.module.business.oa.invoice.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import net.lab1024.sa.base.module.support.datatracer.annoation.DataTracerFieldLabel; + +import java.time.LocalDateTime; + +/** + * OA发票信息 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-06-23 19:32:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_oa_invoice") +public class InvoiceEntity { + + /** + * 发票信息ID + */ + @TableId(type = IdType.AUTO) + private Long invoiceId; + + /** + * 开票抬头 + */ + @DataTracerFieldLabel("开票抬头") + private String invoiceHeads; + + /** + * 纳税人识别号 + */ + @DataTracerFieldLabel("纳税人识别号") + private String taxpayerIdentificationNumber; + + /** + * 银行账户 + */ + @DataTracerFieldLabel("银行账户") + private String accountNumber; + + /** + * 开户行 + */ + @DataTracerFieldLabel("开户行") + private String bankName; + + /** + * 备注 + */ + @DataTracerFieldLabel("备注") + private String remark; + + /** + * 企业ID + */ + private Long enterpriseId; + + /** + * 禁用状态 + */ + @DataTracerFieldLabel("禁用状态") + private Boolean disabledFlag; + + /** + * 删除状态 + */ + @DataTracerFieldLabel("删除状态") + private Boolean deletedFlag; + + /** + * 创建人ID + */ + private Long createUserId; + + /** + * 创建人ID + */ + private String createUserName; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceQueryForm.java new file mode 100644 index 0000000..497778f --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceQueryForm.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.oa.invoice.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; +import org.hibernate.validator.constraints.Length; + +import java.time.LocalDate; + +/** + * OA发票信息查询 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-06-23 19:32:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class InvoiceQueryForm extends PageParam { + + @Schema(description = "企业ID") + private Long enterpriseId; + + @Schema(description = "关键字") + @Length(max = 200, message = "关键字最多200字符") + private String keywords; + + @Schema(description = "开始时间") + private LocalDate startTime; + + @Schema(description = "结束时间") + private LocalDate endTime; + + @Schema(description = "禁用状态") + private Boolean disabledFlag; + + @Schema(description = "删除状态", hidden = true) + private Boolean deletedFlag; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceUpdateForm.java new file mode 100644 index 0000000..a8c6d6c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceUpdateForm.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.business.oa.invoice.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * OA发票信息编辑 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-06-23 19:32:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class InvoiceUpdateForm extends InvoiceAddForm { + + @Schema(description = "发票信息ID") + @NotNull(message = "发票信息ID不能为空") + private Long invoiceId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceVO.java new file mode 100644 index 0000000..2e9e645 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/domain/InvoiceVO.java @@ -0,0 +1,58 @@ +package net.lab1024.sa.admin.module.business.oa.invoice.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * OA发票信息 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-06-23 19:32:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class InvoiceVO { + + @Schema(description = "发票信息ID") + private Long invoiceId; + + @Schema(description = "开票抬头") + private String invoiceHeads; + + @Schema(description = "纳税人识别号") + private String taxpayerIdentificationNumber; + + @Schema(description = "银行账户") + private String accountNumber; + + @Schema(description = "开户行") + private String bankName; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "企业") + private Long enterpriseId; + + @Schema(description = "企业名称") + private String enterpriseName; + + @Schema(description = "禁用状态") + private Boolean disabledFlag; + + @Schema(description = "创建人ID") + private Long createUserId; + + @Schema(description = "创建人名称") + private String createUserName; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/service/InvoiceService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/service/InvoiceService.java new file mode 100644 index 0000000..dc7eb52 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/invoice/service/InvoiceService.java @@ -0,0 +1,144 @@ +package net.lab1024.sa.admin.module.business.oa.invoice.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.module.business.oa.enterprise.service.EnterpriseService; +import net.lab1024.sa.admin.module.business.oa.enterprise.domain.vo.EnterpriseVO; +import net.lab1024.sa.admin.module.business.oa.invoice.dao.InvoiceDao; +import net.lab1024.sa.admin.module.business.oa.invoice.domain.*; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerConst; +import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerTypeEnum; +import net.lab1024.sa.base.module.support.datatracer.service.DataTracerService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; + +/** + * OA发票信息 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-06-23 19:32:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +@Slf4j +public class InvoiceService { + + @Resource + private InvoiceDao invoiceDao; + + @Resource + private EnterpriseService enterpriseService; + + @Resource + private DataTracerService dataTracerService; + + /** + * 分页查询发票信息 + */ + public ResponseDTO> queryByPage(InvoiceQueryForm queryForm) { + queryForm.setDeletedFlag(Boolean.FALSE); + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List invoiceList = invoiceDao.queryPage(page, queryForm); + PageResult pageResult = SmartPageUtil.convert2PageResult(page, invoiceList); + return ResponseDTO.ok(pageResult); + } + + public ResponseDTO> queryList(Long enterpriseId) { + InvoiceQueryForm queryForm = new InvoiceQueryForm(); + queryForm.setDeletedFlag(Boolean.FALSE); + queryForm.setDisabledFlag(Boolean.FALSE); + queryForm.setEnterpriseId(enterpriseId); + List invoiceList = invoiceDao.queryPage(null, queryForm); + return ResponseDTO.ok(invoiceList); + } + + /** + * 查询发票信息详情 + */ + public ResponseDTO getDetail(Long invoiceId) { + // 校验发票信息是否存在 + InvoiceVO invoiceVO = invoiceDao.getDetail(invoiceId, Boolean.FALSE); + if (Objects.isNull(invoiceVO)) { + return ResponseDTO.userErrorParam("发票信息不存在"); + } + return ResponseDTO.ok(invoiceVO); + } + + /** + * 新建发票信息 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO createInvoice(InvoiceAddForm createVO) { + Long enterpriseId = createVO.getEnterpriseId(); + // 校验企业是否存在 + EnterpriseVO enterpriseVO = enterpriseService.getDetail(enterpriseId); + if (Objects.isNull(enterpriseVO)) { + return ResponseDTO.userErrorParam("企业不存在"); + } + // 验证发票信息账号是否重复 + InvoiceEntity validateInvoice = invoiceDao.queryByAccountNumber(enterpriseId, createVO.getAccountNumber(), null, Boolean.FALSE); + if (Objects.nonNull(validateInvoice)) { + return ResponseDTO.userErrorParam("发票信息账号重复"); + } + // 数据插入 + InvoiceEntity insertInvoice = SmartBeanUtil.copy(createVO, InvoiceEntity.class); + invoiceDao.insert(insertInvoice); + dataTracerService.addTrace(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE, "新增发票:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(insertInvoice)); + return ResponseDTO.ok(); + } + + /** + * 编辑发票信息 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO updateInvoice(InvoiceUpdateForm updateVO) { + Long enterpriseId = updateVO.getEnterpriseId(); + // 校验企业是否存在 + EnterpriseVO enterpriseVO = enterpriseService.getDetail(enterpriseId); + if (Objects.isNull(enterpriseVO)) { + return ResponseDTO.userErrorParam("企业不存在"); + } + Long invoiceId = updateVO.getInvoiceId(); + // 校验发票信息是否存在 + InvoiceEntity invoiceDetail = invoiceDao.selectById(invoiceId); + if (Objects.isNull(invoiceDetail) || invoiceDetail.getDeletedFlag()) { + return ResponseDTO.userErrorParam("发票信息不存在"); + } + // 验证发票信息账号是否重复 + InvoiceEntity validateInvoice = invoiceDao.queryByAccountNumber(updateVO.getEnterpriseId(), updateVO.getAccountNumber(), invoiceId, Boolean.FALSE); + if (Objects.nonNull(validateInvoice)) { + return ResponseDTO.userErrorParam("发票信息账号重复"); + } + // 数据编辑 + InvoiceEntity updateInvoice = SmartBeanUtil.copy(updateVO, InvoiceEntity.class); + invoiceDao.updateById(updateInvoice); + dataTracerService.addTrace(enterpriseId, DataTracerTypeEnum.OA_ENTERPRISE, "更新发票:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(invoiceDetail, updateInvoice)); + return ResponseDTO.ok(); + } + + + /** + * 删除发票信息 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO deleteInvoice(Long invoiceId) { + // 校验发票信息是否存在 + InvoiceEntity invoiceDetail = invoiceDao.selectById(invoiceId); + if (Objects.isNull(invoiceDetail) || invoiceDetail.getDeletedFlag()) { + return ResponseDTO.userErrorParam("发票信息不存在"); + } + invoiceDao.deleteInvoice(invoiceId, Boolean.TRUE); + dataTracerService.addTrace(invoiceDetail.getEnterpriseId(), DataTracerTypeEnum.OA_ENTERPRISE, "删除发票:" + DataTracerConst.HTML_BR + dataTracerService.getChangeContent(invoiceDetail)); + return ResponseDTO.ok(); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/constant/NoticeVisibleRangeDataTypeEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/constant/NoticeVisibleRangeDataTypeEnum.java new file mode 100644 index 0000000..eb4784f --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/constant/NoticeVisibleRangeDataTypeEnum.java @@ -0,0 +1,36 @@ +package net.lab1024.sa.admin.module.business.oa.notice.constant; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 公告、通知 可见范围类型 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Getter +@AllArgsConstructor +public enum NoticeVisibleRangeDataTypeEnum implements BaseEnum { + + /** + * 员工 + */ + EMPLOYEE(1, "员工"), + + /** + * 部门 + */ + DEPARTMENT(2, "部门"), + + ; + + private final Integer value; + + private final String desc; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/controller/NoticeController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/controller/NoticeController.java new file mode 100644 index 0000000..78fb7bd --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/controller/NoticeController.java @@ -0,0 +1,140 @@ +package net.lab1024.sa.admin.module.business.oa.notice.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.extra.servlet.JakartaServletUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.*; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.*; +import net.lab1024.sa.admin.module.business.oa.notice.service.NoticeEmployeeService; +import net.lab1024.sa.admin.module.business.oa.notice.service.NoticeService; +import net.lab1024.sa.admin.module.business.oa.notice.service.NoticeTypeService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.module.support.operatelog.annotation.OperateLog; +import net.lab1024.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 公告、通知、新闻等等 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat 卓大1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Tag(name = AdminSwaggerTagConst.Business.OA_NOTICE) +@RestController +@OperateLog +public class NoticeController { + + @Resource + private NoticeService noticeService; + + @Resource + private NoticeTypeService noticeTypeService; + + @Resource + private NoticeEmployeeService noticeEmployeeService; + + // --------------------- 通知公告类型 ------------------------- + + @Operation(summary = "通知公告类型-获取全部 @author 卓大") + @GetMapping("/oa/noticeType/getAll") + public ResponseDTO> getAll() { + return ResponseDTO.ok(noticeTypeService.getAll()); + } + + @Operation(summary = "通知公告类型-添加 @author 卓大") + @GetMapping("/oa/noticeType/add/{name}") + public ResponseDTO add(@PathVariable String name) { + return noticeTypeService.add(name); + } + + @Operation(summary = "通知公告类型-修改 @author 卓大") + @GetMapping("/oa/noticeType/update/{noticeTypeId}/{name}") + public ResponseDTO update(@PathVariable Long noticeTypeId, @PathVariable String name) { + return noticeTypeService.update(noticeTypeId, name); + } + + @Operation(summary = "通知公告类型-删除 @author 卓大") + @GetMapping("/oa/noticeType/delete/{noticeTypeId}") + public ResponseDTO deleteNoticeType(@PathVariable Long noticeTypeId) { + return noticeTypeService.delete(noticeTypeId); + } + + // --------------------- 【管理】通知公告------------------------- + + + @Operation(summary = "【管理】通知公告-分页查询 @author 卓大") + @PostMapping("/oa/notice/query") + @SaCheckPermission("oa:notice:query") + public ResponseDTO> query(@RequestBody @Valid NoticeQueryForm queryForm) { + return ResponseDTO.ok(noticeService.query(queryForm)); + } + + @Operation(summary = "【管理】通知公告-添加 @author 卓大") + @PostMapping("/oa/notice/add") + @RepeatSubmit + @SaCheckPermission("oa:notice:add") + public ResponseDTO add(@RequestBody @Valid NoticeAddForm addForm) { + addForm.setCreateUserId(SmartRequestUtil.getRequestUserId()); + return noticeService.add(addForm); + } + + @Operation(summary = "【管理】通知公告-更新 @author 卓大") + @PostMapping("/oa/notice/update") + @RepeatSubmit + @SaCheckPermission("oa:notice:update") + public ResponseDTO update(@RequestBody @Valid NoticeUpdateForm updateForm) { + return noticeService.update(updateForm); + } + + @Operation(summary = "【管理】通知公告-更新详情 @author 卓大") + @GetMapping("/oa/notice/getUpdateVO/{noticeId}") + @SaCheckPermission("oa:notice:update") + public ResponseDTO getUpdateFormVO(@PathVariable Long noticeId) { + return ResponseDTO.ok(noticeService.getUpdateFormVO(noticeId)); + } + + @Operation(summary = "【管理】通知公告-删除 @author 卓大") + @GetMapping("/oa/notice/delete/{noticeId}") + @SaCheckPermission("oa:notice:delete") + public ResponseDTO delete(@PathVariable Long noticeId) { + return noticeService.delete(noticeId); + } + + // --------------------- 【员工】查看 通知公告 ------------------------- + + + @Operation(summary = "【员工】通知公告-查看详情 @author 卓大") + @GetMapping("/oa/notice/employee/view/{noticeId}") + public ResponseDTO view(@PathVariable Long noticeId, HttpServletRequest request) { + return noticeEmployeeService.view( + SmartRequestUtil.getRequestUserId(), + noticeId, + JakartaServletUtil.getClientIP(request), + request.getHeader("User-Agent") + ); + } + + @Operation(summary = "【员工】通知公告-查询全部 @author 卓大") + @PostMapping("/oa/notice/employee/query") + public ResponseDTO> queryEmployeeNotice(@RequestBody @Valid NoticeEmployeeQueryForm noticeEmployeeQueryForm) { + return noticeEmployeeService.queryList(SmartRequestUtil.getRequestUserId(), noticeEmployeeQueryForm); + } + + @Operation(summary = "【员工】通知公告-查询 查看记录 @author 卓大") + @PostMapping("/oa/notice/employee/queryViewRecord") + public ResponseDTO> queryViewRecord(@RequestBody @Valid NoticeViewRecordQueryForm noticeViewRecordQueryForm) { + return ResponseDTO.ok(noticeEmployeeService.queryViewRecord(noticeViewRecordQueryForm)); + } +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/dao/NoticeDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/dao/NoticeDao.java new file mode 100644 index 0000000..c3609d6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/dao/NoticeDao.java @@ -0,0 +1,126 @@ +package net.lab1024.sa.admin.module.business.oa.notice.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.business.oa.notice.domain.entity.NoticeEntity; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeEmployeeQueryForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeQueryForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeViewRecordQueryForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeVisibleRangeForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeEmployeeVO; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeVO; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeViewRecordVO; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeVisibleRangeVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 公告、通知、新闻等等 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface NoticeDao extends BaseMapper { + + // ================================= 数据范围相关 【子表】 ================================= + + /** + * 保存可见范围 + * + */ + void insertVisibleRange(@Param("noticeId") Long noticeId, @Param("visibleRangeFormList") List visibleRangeFormList); + + /** + * 删除可见范围 + * + */ + void deleteVisibleRange(@Param("noticeId") Long noticeId); + + /** + * 相关可见范围 + * + */ + List queryVisibleRange(@Param("noticeId") Long noticeId); + + // ================================= 通知公告【主表】 相关 ================================= + + /** + * 后管分页查询资讯 + * + */ + List query(Page page, @Param("query") NoticeQueryForm queryForm); + + + /** + * 更新删除状态 + * + */ + void updateDeletedFlag(@Param("noticeId") Long noticeId); + + // ================================= 通知公告【员工查看】 相关 ================================= + + /** + * 查询 员工 查看到的通知公告 + * + */ + List queryEmployeeNotice(Page page, + @Param("requestEmployeeId") Long requestEmployeeId, + @Param("query") NoticeEmployeeQueryForm noticeEmployeeQueryForm, + @Param("requestEmployeeDepartmentIdList") List requestEmployeeDepartmentIdList, + @Param("deletedFlag") boolean deletedFlag, + @Param("administratorFlag") boolean administratorFlag, + @Param("departmentDataType") Integer departmentDataType, + @Param("employeeDataType") Integer employeeDataType + + ); + + /** + * 查询 员工 未读的通知公告 + * + */ + List queryEmployeeNotViewNotice(Page page, + @Param("requestEmployeeId") Long requestEmployeeId, + @Param("query") NoticeEmployeeQueryForm noticeEmployeeQueryForm, + @Param("requestEmployeeDepartmentIdList") List requestEmployeeDepartmentIdList, + @Param("deletedFlag") boolean deletedFlag, + @Param("administratorFlag") boolean administratorFlag, + @Param("departmentDataType") Integer departmentDataType, + @Param("employeeDataType") Integer employeeDataType + + ); + + long viewRecordCount(@Param("noticeId")Long noticeId, @Param("employeeId")Long employeeId); + + /** + * 查询通知、公告的 查看记录 + */ + List queryNoticeViewRecordList(Page page,@Param("queryForm") NoticeViewRecordQueryForm noticeViewRecordQueryForm); + + /** + * 保存查看记录 + */ + void insertViewRecord(@Param("noticeId") Long noticeId, @Param("employeeId") Long employeeId, @Param("ip") String ip, @Param("userAgent") String userAgent,@Param("pageViewCount") Integer pageViewCount); + + /** + * 更新查看记录 + */ + void updateViewRecord(@Param("noticeId")Long noticeId, @Param("employeeId")Long requestEmployeeId,@Param("ip") String ip, @Param("userAgent")String userAgent); + + /** + * 更新 浏览量 + * + * @param noticeId 通知 id + * @param pageViewCountIncrement 页面浏览量的增量 + * @param userViewCountIncrement 用户浏览量的增量 + */ + void updateViewCount(@Param("noticeId")Long noticeId,@Param("pageViewCountIncrement") Integer pageViewCountIncrement, @Param("userViewCountIncrement")Integer userViewCountIncrement); + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/dao/NoticeTypeDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/dao/NoticeTypeDao.java new file mode 100644 index 0000000..7f7ee5c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/dao/NoticeTypeDao.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.oa.notice.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.lab1024.sa.admin.module.business.oa.notice.domain.entity.NoticeTypeEntity; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Component; + +/** + * 通知公告类型 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface NoticeTypeDao extends BaseMapper { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/entity/NoticeEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/entity/NoticeEntity.java new file mode 100644 index 0000000..191d0bf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/entity/NoticeEntity.java @@ -0,0 +1,99 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 通知公告 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_notice") +public class NoticeEntity { + + @TableId(type = IdType.AUTO) + private Long noticeId; + + /** + * 类型 + */ + private Long noticeTypeId; + + /** + * 标题 + */ + private String title; + + /** + * 是否全部可见 + */ + private Boolean allVisibleFlag; + + /** + * 是否定时发布 + */ + private Boolean scheduledPublishFlag; + + /** + * 发布时间 + */ + private LocalDateTime publishTime; + + /** + * 内容 纯文本 + */ + private String contentText; + + /** + * 内容 html + */ + private String contentHtml; + + /** + * 附件 + * 多个英文逗号分隔 + */ + private String attachment; + + /** + * 页面浏览量 + */ + private Integer pageViewCount; + + /** + * 用户浏览量 + */ + private Integer userViewCount; + + /** + * 来源 + */ + private String source; + + /** + * 作者 + */ + private String author; + + /** + * 文号 + */ + private String documentNumber; + + private Boolean deletedFlag; + + private Long createUserId; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/entity/NoticeTypeEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/entity/NoticeTypeEntity.java new file mode 100644 index 0000000..4e9922d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/entity/NoticeTypeEntity.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +/** + * 通知公告类型 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_notice_type") +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class NoticeTypeEntity { + + @TableId(type = IdType.AUTO) + private Long noticeTypeId; + + /** + * 名称 + */ + private String noticeTypeName; + + + private LocalDateTime updateTime; + + private LocalDateTime createTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeAddForm.java new file mode 100644 index 0000000..1bd1fe3 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeAddForm.java @@ -0,0 +1,78 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.form; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.base.common.json.deserializer.FileKeyVoDeserializer; +import org.hibernate.validator.constraints.Length; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 通知公告 添加表单 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeAddForm { + + @Schema(description = "标题") + @NotBlank(message = "标题不能为空") + @Length(max = 200, message = "标题最多200字符") + private String title; + + @Schema(description = "分类") + @NotNull(message = "分类不能为空") + private Long noticeTypeId; + + @Schema(description = "是否全部可见") + @NotNull(message = "是否全部可见不能为空") + private Boolean allVisibleFlag; + + @Schema(description = "是否定时发布") + @NotNull(message = "是否定时发布不能为空") + private Boolean scheduledPublishFlag; + + @Schema(description = "发布时间") + @NotNull(message = "发布时间不能为空") + private LocalDateTime publishTime; + + @Schema(description = "纯文本内容") + @NotNull(message = "文本内容不能为空") + private String contentText; + + @Schema(description = "html内容") + @NotNull(message = "html内容不能为空") + private String contentHtml; + + @Schema(description = "附件,多个英文逗号分隔|可选") + @Length(max = 1000, message = "最多1000字符") + @JsonDeserialize(using = FileKeyVoDeserializer.class) + private String attachment; + + @Schema(description = "作者") + @NotBlank(message = "作者不能为空") + private String author; + + @Schema(description = "来源") + @NotBlank(message = "标题不能为空") + private String source; + + @Schema(description = "文号") + private String documentNumber; + + @Schema(hidden = true) + private Long createUserId; + + @Schema(description = "可见范围设置|可选") + @Valid + private List visibleRangeList; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeEmployeeQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeEmployeeQueryForm.java new file mode 100644 index 0000000..3f3d90b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeEmployeeQueryForm.java @@ -0,0 +1,35 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; + +import java.time.LocalDate; + +/** + * 通知公告 员工查询表单 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeEmployeeQueryForm extends PageParam { + + @Schema(description = "标题、作者、来源、文号") + private String keywords; + + @Schema(description = "分类") + private Long noticeTypeId; + + @Schema(description = "发布-开始时间") + private LocalDate publishTimeBegin; + + @Schema(description = "未读标识") + private Boolean notViewFlag; + + @Schema(description = "发布-截止时间") + private LocalDate publishTimeEnd; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeQueryForm.java new file mode 100644 index 0000000..1e9544b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeQueryForm.java @@ -0,0 +1,48 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; + +import java.time.LocalDate; + +/** + * 通知公告 管理查询表单 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeQueryForm extends PageParam { + + @Schema(description = "分类") + private Long noticeTypeId; + + @Schema(description = "标题、作者、来源") + private String keywords; + + @Schema(description = "文号") + private String documentNumber; + + @Schema(description = "创建人") + private String createUserName; + + @Schema(description = "删除标识") + private Boolean deletedFlag; + + @Schema(description = "创建-开始时间") + private LocalDate createTimeBegin; + + @Schema(description = "创建-截止时间") + private LocalDate createTimeEnd; + + @Schema(description = "发布-开始时间") + private LocalDate publishTimeBegin; + + @Schema(description = "发布-截止时间") + private LocalDate publishTimeEnd; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeUpdateForm.java new file mode 100644 index 0000000..13d7553 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeUpdateForm.java @@ -0,0 +1,23 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 通知公告 更新表单 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeUpdateForm extends NoticeAddForm { + + @Schema(description = "id") + @NotNull(message = "通知id不能为空") + private Long noticeId; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeViewRecordQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeViewRecordQueryForm.java new file mode 100644 index 0000000..415828c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeViewRecordQueryForm.java @@ -0,0 +1,31 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; + +/** + * 通知公告 阅读记录查询 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeViewRecordQueryForm extends PageParam { + + @Schema(description = "通知公告id") + @NotNull(message = "通知公告id不能为空") + private Long noticeId; + + @Schema(description = "部门id") + private Long departmentId; + + @Schema(description = "关键字") + private String keywords; + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeVisibleRangeForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeVisibleRangeForm.java new file mode 100644 index 0000000..c831db6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/form/NoticeVisibleRangeForm.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import net.lab1024.sa.admin.module.business.oa.notice.constant.NoticeVisibleRangeDataTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; + +/** + * 通知公告 可见范围数据 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class NoticeVisibleRangeForm { + + @SchemaEnum(NoticeVisibleRangeDataTypeEnum.class) + @CheckEnum(value = NoticeVisibleRangeDataTypeEnum.class, required = true, message = "数据类型错误") + private Integer dataType; + + @Schema(description = "员工/部门id") + @NotNull(message = "员工/部门id不能为空") + private Long dataId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeDetailVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeDetailVO.java new file mode 100644 index 0000000..096a0d0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeDetailVO.java @@ -0,0 +1,84 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer; + +import java.time.LocalDateTime; + +/** + * 通知公告 详情 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeDetailVO { + + @Schema(description = "id") + private Long noticeId; + + @Schema(description = "标题") + private String title; + + @Schema(description = "分类") + private Long noticeTypeId; + + @Schema(description = "分类名称") + private Long noticeTypeName; + + @Schema(description = "是否全部可见") + @NotNull(message = "是否全部可见不能为空") + private Boolean allVisibleFlag; + + @Schema(description = "是否定时发布") + @NotNull(message = "是否定时发布不能为空") + private Boolean scheduledPublishFlag; + + @Schema(description = "纯文本内容") + private String contentText; + + @Schema(description = "html内容") + private String contentHtml; + + @Schema(description = "附件") + @JsonSerialize(using = FileKeyVoSerializer.class) + private String attachment; + + @Schema(description = "发布时间") + @NotNull(message = "发布时间不能为空") + private LocalDateTime publishTime; + + @Schema(description = "作者") + @NotBlank(message = "作者不能为空") + private String author; + + @Schema(description = "来源") + @NotBlank(message = "标题不能为空") + private String source; + + @Schema(description = "文号") + private String documentNumber; + + @Schema(description = "页面浏览量") + private Integer pageViewCount; + + @Schema(description = "用户浏览量") + private Integer userViewCount; + + @Schema(description = "创建人名称") + private Long createUserName; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeEmployeeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeEmployeeVO.java new file mode 100644 index 0000000..759ba6c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeEmployeeVO.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; + +/** + * 通知公告 员工查看 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeEmployeeVO extends NoticeVO { + + @Schema(description = "是否查看") + private Boolean viewFlag; + + @Schema(description = "发布日期") + private LocalDate publishDate; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeTypeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeTypeVO.java new file mode 100644 index 0000000..2660959 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeTypeVO.java @@ -0,0 +1,24 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 通知公告 类型 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeTypeVO { + + @Schema(description = "通知类型id") + private Long noticeTypeId; + + @Schema(description = "通知类型-名称") + private String noticeTypeName; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeUpdateFormVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeUpdateFormVO.java new file mode 100644 index 0000000..1302559 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeUpdateFormVO.java @@ -0,0 +1,35 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.json.serializer.FileKeyVoSerializer; + +import java.util.List; + +/** + * 用于更新 【通知、公告】 的 VO 对象 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeUpdateFormVO extends NoticeVO { + + @Schema(description = "纯文本内容") + private String contentText; + + @Schema(description = "html内容") + private String contentHtml; + + @Schema(description = "附件") + @JsonSerialize(using = FileKeyVoSerializer.class) + private String attachment; + + @Schema(description = "可见范围") + private List visibleRangeList; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java new file mode 100644 index 0000000..b67100e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVO.java @@ -0,0 +1,72 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + + +/** + * 新闻、公告 VO + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeVO { + + @Schema(description = "id") + private Long noticeId; + + @Schema(description = "标题") + private String title; + + @Schema(description = "分类") + private Long noticeTypeId; + + @Schema(description = "分类名称") + private String noticeTypeName; + + @Schema(description = "是否全部可见") + private Boolean allVisibleFlag; + + @Schema(description = "是否定时发布") + private Boolean scheduledPublishFlag; + + @Schema(description = "发布状态") + private Boolean publishFlag; + + @Schema(description = "发布时间") + private LocalDateTime publishTime; + + @Schema(description = "作者") + private String author; + + @Schema(description = "来源") + private String source; + + @Schema(description = "文号") + private String documentNumber; + + @Schema(description = "页面浏览量") + private Integer pageViewCount; + + @Schema(description = "用户浏览量") + private Integer userViewCount; + + @Schema(description = "删除标识") + private Boolean deletedFlag; + + @Schema(description = "创建人名称") + private String createUserName; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeViewRecordVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeViewRecordVO.java new file mode 100644 index 0000000..23b1adc --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeViewRecordVO.java @@ -0,0 +1,49 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 浏览记录 VO + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeViewRecordVO { + + @Schema(description = "员工ID") + private Long employeeId; + + @Schema(description = "员工姓名") + private String employeeName; + + @Schema(description = "员工部门名称") + private String departmentName; + + @Schema(description = "查看次数") + private Integer pageViewCount; + + @Schema(description = "首次ip") + private String firstIp; + + @Schema(description = "首次用户设备等标识") + private String firstUserAgent; + + @Schema(description = "首次查看时间") + private LocalDateTime createTime; + + @Schema(description = "最后一次 ip") + private String lastIp; + + @Schema(description = "最后一次 用户设备等标识") + private String lastUserAgent; + + @Schema(description = "最后一次查看时间") + private LocalDateTime updateTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVisibleRangeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVisibleRangeVO.java new file mode 100644 index 0000000..0206cad --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/domain/vo/NoticeVisibleRangeVO.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.admin.module.business.oa.notice.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.business.oa.notice.constant.NoticeVisibleRangeDataTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; + +/** + * 新闻、公告 可见范围数据 VO + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class NoticeVisibleRangeVO { + + @SchemaEnum(NoticeVisibleRangeDataTypeEnum.class) + private Integer dataType; + + @Schema(description = "员工/部门id") + private Long dataId; + + @Schema(description = "员工/部门 名称") + private String dataName; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/manager/NoticeManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/manager/NoticeManager.java new file mode 100644 index 0000000..78b02e1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/manager/NoticeManager.java @@ -0,0 +1,62 @@ +package net.lab1024.sa.admin.module.business.oa.notice.manager; + +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.oa.notice.dao.NoticeDao; +import net.lab1024.sa.admin.module.business.oa.notice.domain.entity.NoticeEntity; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeVisibleRangeForm; +import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerTypeEnum; +import net.lab1024.sa.base.module.support.datatracer.service.DataTracerService; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 通知、公告 manager + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class NoticeManager { + + @Resource + private NoticeDao noticeDao; + + @Resource + private DataTracerService dataTracerService; + + /** + * 保存 + */ + @Transactional(rollbackFor = Throwable.class) + public void save(NoticeEntity noticeEntity, List visibleRangeFormList) { + noticeDao.insert(noticeEntity); + Long noticeId = noticeEntity.getNoticeId(); + // 保存可见范围 + if (CollectionUtils.isNotEmpty(visibleRangeFormList)) { + noticeDao.insertVisibleRange(noticeId, visibleRangeFormList); + } + dataTracerService.insert(noticeId, DataTracerTypeEnum.OA_NOTICE); + } + + /** + * 更新 + * + */ + @Transactional(rollbackFor = Throwable.class) + public void update(NoticeEntity old, NoticeEntity noticeEntity, List visibleRangeList) { + noticeDao.updateById(noticeEntity); + Long noticeId = noticeEntity.getNoticeId(); + // 保存可见范围 + if (CollectionUtils.isNotEmpty(visibleRangeList)) { + noticeDao.deleteVisibleRange(noticeId); + noticeDao.insertVisibleRange(noticeId, visibleRangeList); + } + dataTracerService.update(noticeId, DataTracerTypeEnum.OA_NOTICE, old, noticeEntity); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeEmployeeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeEmployeeService.java new file mode 100644 index 0000000..2f2404d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeEmployeeService.java @@ -0,0 +1,155 @@ +package net.lab1024.sa.admin.module.business.oa.notice.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.oa.notice.constant.NoticeVisibleRangeDataTypeEnum; +import net.lab1024.sa.admin.module.business.oa.notice.dao.NoticeDao; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeEmployeeQueryForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeViewRecordQueryForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.*; +import net.lab1024.sa.admin.module.system.department.service.DepartmentService; +import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; +import net.lab1024.sa.admin.module.system.employee.service.EmployeeService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + + +/** + * 员工查看 通知。公告 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class NoticeEmployeeService { + + @Resource + private NoticeDao noticeDao; + + @Resource + private NoticeService noticeService; + + @Resource + private DepartmentService departmentService; + + @Resource + private EmployeeService employeeService; + + /** + * 查询我的 通知、公告清单 + */ + public ResponseDTO> queryList(Long requestEmployeeId, NoticeEmployeeQueryForm noticeEmployeeQueryForm) { + Page page = SmartPageUtil.convert2PageQuery(noticeEmployeeQueryForm); + + List employeeDepartmentIdList = Lists.newArrayList(); + EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId); + // 如果不是管理员 则获取请求人的 部门及其子部门 + if (!employeeEntity.getAdministratorFlag() && employeeEntity.getDepartmentId() != null) { + employeeDepartmentIdList = departmentService.selfAndChildrenIdList(employeeEntity.getDepartmentId()); + } + + List noticeList = null; + //只查询未读的 + if (noticeEmployeeQueryForm.getNotViewFlag() != null && noticeEmployeeQueryForm.getNotViewFlag()) { + noticeList = noticeDao.queryEmployeeNotViewNotice(page, + requestEmployeeId, + noticeEmployeeQueryForm, + employeeDepartmentIdList, + false, + employeeEntity.getAdministratorFlag(), + NoticeVisibleRangeDataTypeEnum.DEPARTMENT.getValue(), + NoticeVisibleRangeDataTypeEnum.EMPLOYEE.getValue()); + } else { + // 查询全部 + noticeList = noticeDao.queryEmployeeNotice(page, + requestEmployeeId, + noticeEmployeeQueryForm, + employeeDepartmentIdList, + false, + employeeEntity.getAdministratorFlag(), + NoticeVisibleRangeDataTypeEnum.DEPARTMENT.getValue(), + NoticeVisibleRangeDataTypeEnum.EMPLOYEE.getValue()); + } + // 设置发布日期 + noticeList.forEach(notice -> notice.setPublishDate(notice.getPublishTime().toLocalDate())); + + return ResponseDTO.ok(SmartPageUtil.convert2PageResult(page, noticeList)); + } + + + /** + * 查询我的 待查看的 通知、公告清单 + */ + public ResponseDTO view(Long requestEmployeeId, Long noticeId, String ip, String userAgent) { + NoticeUpdateFormVO updateFormVO = noticeService.getUpdateFormVO(noticeId); + if (updateFormVO == null || Boolean.TRUE.equals(updateFormVO.getDeletedFlag())) { + return ResponseDTO.userErrorParam("通知公告不存在"); + } + + EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId); + if (!updateFormVO.getAllVisibleFlag() && !checkVisibleRange(updateFormVO.getVisibleRangeList(), requestEmployeeId, employeeEntity.getDepartmentId())) { + return ResponseDTO.userErrorParam("对不起,您没有权限查看内容"); + } + + NoticeDetailVO noticeDetailVO = SmartBeanUtil.copy(updateFormVO, NoticeDetailVO.class); + long viewCount = noticeDao.viewRecordCount(noticeId, requestEmployeeId); + if (viewCount == 0) { + noticeDao.insertViewRecord(noticeId, requestEmployeeId, ip, userAgent, 1); + // 该员工对于这个通知是第一次查看 页面浏览量+1 用户浏览量+1 + noticeDao.updateViewCount(noticeId, 1, 1); + noticeDetailVO.setPageViewCount(noticeDetailVO.getPageViewCount() + 1); + noticeDetailVO.setUserViewCount(noticeDetailVO.getUserViewCount() + 1); + } else { + noticeDao.updateViewRecord(noticeId, requestEmployeeId, ip, userAgent); + // 该员工对于这个通知不是第一次查看 页面浏览量+1 用户浏览量+0 + noticeDao.updateViewCount(noticeId, 1, 0); + noticeDetailVO.setPageViewCount(noticeDetailVO.getPageViewCount() + 1); + } + + return ResponseDTO.ok(noticeDetailVO); + } + + /** + * 校验是否有查看权限的范围 + * + */ + public boolean checkVisibleRange(List visibleRangeList, Long employeeId, Long departmentId) { + // 员工范围 + boolean anyMatch = visibleRangeList.stream().anyMatch(e -> NoticeVisibleRangeDataTypeEnum.EMPLOYEE.equalsValue(e.getDataType()) && Objects.equals(e.getDataId(), employeeId)); + if (anyMatch) { + return true; + } + + //部门范围 + List visibleDepartmentIdList = visibleRangeList.stream().filter(e -> NoticeVisibleRangeDataTypeEnum.DEPARTMENT.equalsValue(e.getDataType())) + .map(NoticeVisibleRangeVO::getDataId).collect(Collectors.toList()); + + for (Long visibleDepartmentId : visibleDepartmentIdList) { + List departmentIdList = departmentService.selfAndChildrenIdList(visibleDepartmentId); + if (departmentIdList.contains(departmentId)) { + return true; + } + } + return false; + } + + /** + * 分页查询 查看记录 + */ + public PageResult queryViewRecord(NoticeViewRecordQueryForm noticeViewRecordQueryForm) { + Page page = SmartPageUtil.convert2PageQuery(noticeViewRecordQueryForm); + List noticeViewRecordList = noticeDao.queryNoticeViewRecordList(page, noticeViewRecordQueryForm); + return SmartPageUtil.convert2PageResult(page, noticeViewRecordList); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeService.java new file mode 100644 index 0000000..0f7b1b5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeService.java @@ -0,0 +1,240 @@ +package net.lab1024.sa.admin.module.business.oa.notice.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.oa.notice.constant.NoticeVisibleRangeDataTypeEnum; +import net.lab1024.sa.admin.module.business.oa.notice.dao.NoticeDao; +import net.lab1024.sa.admin.module.business.oa.notice.domain.entity.NoticeEntity; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeAddForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeQueryForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeUpdateForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.form.NoticeVisibleRangeForm; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeTypeVO; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeUpdateFormVO; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeVO; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeVisibleRangeVO; +import net.lab1024.sa.admin.module.business.oa.notice.manager.NoticeManager; +import net.lab1024.sa.admin.module.system.department.dao.DepartmentDao; +import net.lab1024.sa.admin.module.system.department.domain.entity.DepartmentEntity; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO; +import net.lab1024.sa.admin.module.system.department.service.DepartmentService; +import net.lab1024.sa.admin.module.system.employee.dao.EmployeeDao; +import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; +import net.lab1024.sa.base.common.constant.StringConst; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.datatracer.constant.DataTracerTypeEnum; +import net.lab1024.sa.base.module.support.datatracer.service.DataTracerService; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 通知。公告 后台管理业务 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class NoticeService { + + @Resource + private NoticeDao noticeDao; + + @Resource + private NoticeManager noticeManager; + + @Resource + private EmployeeDao employeeDao; + + @Resource + private DepartmentDao departmentDao; + + @Resource + private DepartmentService departmentService; + + @Resource + private NoticeTypeService noticeTypeService; + + @Resource + private DataTracerService dataTracerService; + + /** + * 查询 通知、公告 + * + */ + public PageResult query(NoticeQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = noticeDao.query(page, queryForm); + LocalDateTime now = LocalDateTime.now(); + list.forEach(e -> e.setPublishFlag(e.getPublishTime().isBefore(now))); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 添加 + */ + public ResponseDTO add(NoticeAddForm addForm) { + // 校验并获取可见范围 + ResponseDTO validate = this.checkAndBuildVisibleRange(addForm); + if (!validate.getOk()) { + return ResponseDTO.error(validate); + } + + // build 资讯 + NoticeEntity noticeEntity = SmartBeanUtil.copy(addForm, NoticeEntity.class); + // 发布时间:不是定时发布时 默认为 当前 + if (!addForm.getScheduledPublishFlag()) { + noticeEntity.setPublishTime(LocalDateTime.now()); + } + // 保存数据 + noticeManager.save(noticeEntity, addForm.getVisibleRangeList()); + return ResponseDTO.ok(); + } + + /** + * 校验并返回可见范围 + * + */ + private ResponseDTO checkAndBuildVisibleRange(NoticeAddForm form) { + // 校验资讯分类 + NoticeTypeVO noticeType = noticeTypeService.getByNoticeTypeId(form.getNoticeTypeId()); + if (noticeType == null) { + return ResponseDTO.userErrorParam("分类不存在"); + } + + if (form.getAllVisibleFlag()) { + return ResponseDTO.ok(); + } + + /* + * 校验可见范围 + * 非全部可见时 校验选择的员工|部门 + */ + List visibleRangeUpdateList = form.getVisibleRangeList(); + if (CollectionUtils.isEmpty(visibleRangeUpdateList)) { + return ResponseDTO.userErrorParam("未设置可见范围"); + } + + // 校验可见范围-> 员工 + List employeeIdList = visibleRangeUpdateList.stream() + .filter(e -> NoticeVisibleRangeDataTypeEnum.EMPLOYEE.equalsValue(e.getDataType())) + .map(NoticeVisibleRangeForm::getDataId) + .distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(employeeIdList)) { + employeeIdList = employeeIdList.stream().distinct().collect(Collectors.toList()); + List dbEmployeeIdList = employeeDao.selectBatchIds(employeeIdList).stream().map(EmployeeEntity::getEmployeeId).collect(Collectors.toList()); + Collection subtract = CollectionUtils.subtract(employeeIdList, dbEmployeeIdList); + if (!subtract.isEmpty()) { + return ResponseDTO.userErrorParam("员工id不存在:" + subtract); + } + } + + // 校验可见范围-> 部门 + List deptIdList = visibleRangeUpdateList.stream() + .filter(e -> NoticeVisibleRangeDataTypeEnum.DEPARTMENT.equalsValue(e.getDataType())) + .map(NoticeVisibleRangeForm::getDataId) + .distinct().collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(deptIdList)) { + deptIdList = deptIdList.stream().distinct().collect(Collectors.toList()); + List dbDeptIdList = departmentDao.selectBatchIds(deptIdList).stream().map(DepartmentEntity::getDepartmentId).collect(Collectors.toList()); + Collection subtract = CollectionUtils.subtract(deptIdList, dbDeptIdList); + if (!subtract.isEmpty()) { + return ResponseDTO.userErrorParam("部门id不存在:" + subtract); + } + } + return ResponseDTO.ok(); + } + + + /** + * 更新 + * + */ + public ResponseDTO update(NoticeUpdateForm updateForm) { + + NoticeEntity oldNoticeEntity = noticeDao.selectById(updateForm.getNoticeId()); + if (oldNoticeEntity == null) { + return ResponseDTO.userErrorParam("通知不存在"); + } + + // 校验并获取可见范围 + ResponseDTO res = this.checkAndBuildVisibleRange(updateForm); + if (!res.getOk()) { + return ResponseDTO.error(res); + } + + // 更新 + NoticeEntity noticeEntity = SmartBeanUtil.copy(updateForm, NoticeEntity.class); + noticeManager.update(oldNoticeEntity, noticeEntity, updateForm.getVisibleRangeList()); + return ResponseDTO.ok(); + } + + + /** + * 删除 + * + */ + public ResponseDTO delete(Long noticeId) { + NoticeEntity noticeEntity = noticeDao.selectById(noticeId); + if (null == noticeEntity || noticeEntity.getDeletedFlag()) { + return ResponseDTO.userErrorParam("通知公告不存在"); + } + // 更新删除状态 + noticeDao.updateDeletedFlag(noticeId); + dataTracerService.delete(noticeId, DataTracerTypeEnum.OA_NOTICE); + return ResponseDTO.ok(); + } + + /** + * 获取更新表单用的详情 + */ + public NoticeUpdateFormVO getUpdateFormVO(Long noticeId) { + NoticeEntity noticeEntity = noticeDao.selectById(noticeId); + if (null == noticeEntity) { + return null; + } + + NoticeUpdateFormVO updateFormVO = SmartBeanUtil.copy(noticeEntity, NoticeUpdateFormVO.class); + NoticeTypeVO noticeType = noticeTypeService.getByNoticeTypeId(noticeEntity.getNoticeTypeId()); + updateFormVO.setNoticeTypeName(noticeType.getNoticeTypeName()); + updateFormVO.setPublishFlag(updateFormVO.getPublishTime() != null && updateFormVO.getPublishTime().isBefore(LocalDateTime.now())); + + if (!updateFormVO.getAllVisibleFlag()) { + List noticeVisibleRangeList = noticeDao.queryVisibleRange(noticeId); + List employeeIdList = noticeVisibleRangeList.stream().filter(e -> NoticeVisibleRangeDataTypeEnum.EMPLOYEE.getValue().equals(e.getDataType())) + .map(NoticeVisibleRangeVO::getDataId) + .collect(Collectors.toList()); + + Map employeeMap = null; + if (CollectionUtils.isNotEmpty(employeeIdList)) { + employeeMap = employeeDao.selectBatchIds(employeeIdList).stream().collect(Collectors.toMap(EmployeeEntity::getEmployeeId, Function.identity())); + } else { + employeeMap = Maps.newHashMap(); + } + for (NoticeVisibleRangeVO noticeVisibleRange : noticeVisibleRangeList) { + if (noticeVisibleRange.getDataType().equals(NoticeVisibleRangeDataTypeEnum.EMPLOYEE.getValue())) { + EmployeeEntity employeeEntity = employeeMap.get(noticeVisibleRange.getDataId()); + noticeVisibleRange.setDataName(employeeEntity == null ? StringConst.EMPTY : employeeEntity.getActualName()); + } else { + DepartmentVO departmentVO = departmentService.getDepartmentById(noticeVisibleRange.getDataId()); + noticeVisibleRange.setDataName(departmentVO == null ? StringConst.EMPTY : departmentVO.getDepartmentName()); + } + } + updateFormVO.setVisibleRangeList(noticeVisibleRangeList); + } + return updateFormVO; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeTypeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeTypeService.java new file mode 100644 index 0000000..6e8a311 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/oa/notice/service/NoticeTypeService.java @@ -0,0 +1,87 @@ +package net.lab1024.sa.admin.module.business.oa.notice.service; + +import cn.hutool.core.util.StrUtil; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.business.oa.notice.dao.NoticeTypeDao; +import net.lab1024.sa.admin.module.business.oa.notice.domain.entity.NoticeTypeEntity; +import net.lab1024.sa.admin.module.business.oa.notice.domain.vo.NoticeTypeVO; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 通知。公告 类型 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-12 21:40:39 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class NoticeTypeService { + + @Resource + private NoticeTypeDao noticeTypeDao; + + /** + * 查询全部 + * @return + */ + public List getAll() { + return SmartBeanUtil.copyList(noticeTypeDao.selectList(null), NoticeTypeVO.class); + } + + public NoticeTypeVO getByNoticeTypeId(Long noticceTypeId) { + return SmartBeanUtil.copy(noticeTypeDao.selectById(noticceTypeId), NoticeTypeVO.class); + } + + public synchronized ResponseDTO add(String name) { + if (StrUtil.isBlank(name)) { + return ResponseDTO.userErrorParam("类型名称不能为空"); + } + + List noticeTypeEntityList = noticeTypeDao.selectList(null); + if (!CollectionUtils.isEmpty(noticeTypeEntityList)) { + boolean exist = noticeTypeEntityList.stream().map(NoticeTypeEntity::getNoticeTypeName).collect(Collectors.toSet()).contains(name); + if (exist) { + return ResponseDTO.userErrorParam("类型名称已经存在"); + } + } + noticeTypeDao.insert(NoticeTypeEntity.builder().noticeTypeName(name).build()); + return ResponseDTO.ok(); + } + + public synchronized ResponseDTO update(Long noticeTypeId, String name) { + if (StrUtil.isBlank(name)) { + return ResponseDTO.userErrorParam("类型名称不能为空"); + } + + NoticeTypeEntity noticeTypeEntity = noticeTypeDao.selectById(noticeTypeId); + if (noticeTypeEntity == null) { + return ResponseDTO.userErrorParam("类型名称不存在"); + } + + List noticeTypeEntityList = noticeTypeDao.selectList(null); + if (!CollectionUtils.isEmpty(noticeTypeEntityList)) { + Optional optionalNoticeTypeEntity = noticeTypeEntityList.stream().filter(e -> e.getNoticeTypeName().equals(name)).findFirst(); + if (optionalNoticeTypeEntity.isPresent() && !optionalNoticeTypeEntity.get().getNoticeTypeId().equals(noticeTypeId)) { + return ResponseDTO.userErrorParam("类型名称已经存在"); + } + } + noticeTypeEntity.setNoticeTypeName(name); + noticeTypeDao.updateById(noticeTypeEntity); + return ResponseDTO.ok(); + } + + public synchronized ResponseDTO delete(Long noticeTypeId) { + noticeTypeDao.deleteById(noticeTypeId); + return ResponseDTO.ok(); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/controller/StatsCaseClinicalController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/controller/StatsCaseClinicalController.java new file mode 100644 index 0000000..8e09d6b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/controller/StatsCaseClinicalController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.controller; + +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.form.StatsCaseClinicalQueryForm; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalVO; +import net.lab1024.sa.admin.module.business.statsCaseClinical.service.StatsCaseClinicalService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 统计表-病例库-临床 Controller + * + * @Author xing + * @Date 2025-08-06 08:51:26 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "统计表-病例库-临床") +public class StatsCaseClinicalController { + + @Resource + private StatsCaseClinicalService statsCaseClinicalService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/statsCaseClinical/queryPage") + @SaCheckPermission("statsCaseClinical:query") + public ResponseDTO> queryPage(@RequestBody @Valid StatsCaseClinicalQueryForm queryForm) { + return ResponseDTO.ok(statsCaseClinicalService.queryPage(queryForm)); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalDao.java new file mode 100644 index 0000000..12f9745 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalDao.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.form.StatsCaseClinicalQueryForm; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; +import org.springframework.stereotype.Component; + +/** + * 统计表-病例库-临床 Dao + * + * @Author xing + * @Date 2025-08-06 08:51:26 + * @Copyright gdxz + */ + +@Mapper +public interface StatsCaseClinicalDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") StatsCaseClinicalQueryForm queryForm); + + /** + * Inc 自增 + * @param articleId 文章 ID + * @param field 字段名称 + * @param numeral 增加的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical SET ${field} = ${field} + #{numeral} WHERE stats_id = #{statsId}") + int inc(@Param("statsId") Long articleId, @Param("field") String field, @Param("numeral") int numeral); + + /** + * Dec 自减 + * + * @param articleId 文章 ID + * @param field 字段名称 + * @param numeral 减少的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical " + + "SET ${field} = CASE WHEN ${field} >= #{numeral} THEN ${field} - #{numeral} ELSE 0 END " + + "WHERE stats_id = #{statsId}") + int dec(@Param("statsId") Long articleId, @Param("field") String field, @Param("numeral") int numeral); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalDoctorDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalDoctorDao.java new file mode 100644 index 0000000..f9ae555 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalDoctorDao.java @@ -0,0 +1,46 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalDoctorVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; +import org.springframework.stereotype.Component; + +/** + * 统计表-病例库-临床-医生 Dao + * + * @Author xing + * @Date 2025-08-06 09:07:32 + * @Copyright gdxz + */ + +@Mapper +public interface StatsCaseClinicalDoctorDao extends BaseMapper { + + /** + * Inc 自增 + * @param doctorId 文章 ID + * @param field 字段名称 + * @param numeral 增加的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical_doctor SET ${field} = ${field} + #{numeral} WHERE doctor_id = #{doctorId}") + int inc(@Param("doctorId") Long doctorId, @Param("field") String field, @Param("numeral") int numeral); + + /** + * Dec 自减 + * + * @param doctorId 文章 ID + * @param field 字段名称 + * @param numeral 减少的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical_doctor " + + "SET ${field} = CASE WHEN ${field} >= #{numeral} THEN ${field} - #{numeral} ELSE 0 END " + + "WHERE doctor_id = #{doctorId}") + int dec(@Param("doctorId") Long doctorId, @Param("field") String field, @Param("numeral") int numeral); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalHospitalDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalHospitalDao.java new file mode 100644 index 0000000..b5f9aff --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalHospitalDao.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalHospitalEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalHospitalVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; +import org.springframework.stereotype.Component; + +/** + * 统计表-病例库-临床-医院 Dao + * + * @Author xing + * @Date 2025-08-06 17:01:19 + * @Copyright gdxz + */ + +@Mapper +public interface StatsCaseClinicalHospitalDao extends BaseMapper { + + /** + * Inc 自增 + * @param articleId 文章 ID + * @param field 字段名称 + * @param numeral 增加的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical_hospital SET ${field} = ${field} + #{numeral} WHERE hospital_id = #{hospitalId}") + int inc(@Param("hospitalId") Long articleId, @Param("field") String field, @Param("numeral") int numeral); + + /** + * Dec 自减 + * + * @param hospitalId 文章 ID + * @param field 字段名称 + * @param numeral 减少的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical_hospital " + + "SET ${field} = CASE WHEN ${field} >= #{numeral} THEN ${field} - #{numeral} ELSE 0 END " + + "WHERE hospital_id = #{hospitalId}") + int dec(@Param("hospitalId") Long hospitalId, @Param("field") String field, @Param("numeral") int numeral); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalLabelDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalLabelDao.java new file mode 100644 index 0000000..a93bfdf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/dao/StatsCaseClinicalLabelDao.java @@ -0,0 +1,44 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalLabelEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalLabelVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Update; +import org.springframework.stereotype.Component; + +/** + * 统计表-病例库-临床-疾病标签 Dao + * + * @Author xing + * @Date 2025-08-07 09:10:35 + * @Copyright gdxz + */ + +@Mapper +public interface StatsCaseClinicalLabelDao extends BaseMapper { + + /** + * Inc 自增 + * @param field 字段名称 + * @param numeral 增加的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical_label SET ${field} = ${field} + #{numeral} WHERE label_iden = #{labelIden}") + int inc(@Param("labelIden") String labelIden, @Param("field") String field, @Param("numeral") int numeral); + + /** + * Dec 自减 + * + * @param field 字段名称 + * @param numeral 减少的数值 + * @return 更新的行数 + */ + @Update("UPDATE stats_case_clinical_label " + + "SET ${field} = CASE WHEN ${field} >= #{numeral} THEN ${field} - #{numeral} ELSE 0 END " + + "WHERE label_iden = #{labelIden}") + int dec(@Param("labelIden") String labelIden, @Param("field") String field, @Param("numeral") int numeral); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalDoctorEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalDoctorEntity.java new file mode 100644 index 0000000..187c0bf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalDoctorEntity.java @@ -0,0 +1,86 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-临床-医生 实体类 + * + * @Author xing + * @Date 2025-08-06 09:07:32 + * @Copyright gdxz + */ + +@Data +@TableName("stats_case_clinical_doctor") +public class StatsCaseClinicalDoctorEntity { + + /** + * 主键id + */ + @TableId + private Long statsId; + + /** + * 医生id + */ + private Long doctorId; + + /** + * 数量-文章 + */ + private Integer articleNum; + + /** + * 总阅读量-文章 + */ + private Integer articleReadNum; + + /** + * 总收藏量-文章 + */ + private Integer articleCollectNum; + + /** + * 总评论量-文章 + */ + private Integer articleCommentNum; + + /** + * 最后一篇文章发表时间 + */ + private LocalDateTime lastPushDate; + + /** + * 数量-视频 + */ + private Integer videoNum; + + /** + * 总阅读量-视频 + */ + private Integer videoReadNum; + + /** + * 总收藏量-视频 + */ + private Integer videoCollectNum; + + /** + * 总评论量-视频 + */ + private Integer videoCommentNum; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalEntity.java new file mode 100644 index 0000000..4bb442e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalEntity.java @@ -0,0 +1,76 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-临床 实体类 + * + * @Author xing + * @Date 2025-08-06 08:51:26 + * @Copyright gdxz + */ + +@Data +@TableName("stats_case_clinical") +public class StatsCaseClinicalEntity { + + /** + * 主键id + */ + @TableId + private Long statsId; + + /** + * 数量-文章 + */ + private Integer articleNum; + + /** + * 总阅读量-文章 + */ + private Integer articleReadNum; + + /** + * 总收藏量-文章 + */ + private Integer articleCollectNum; + + /** + * 总评论量-文章 + */ + private Integer articleCommentNum; + + /** + * 数量-视频 + */ + private Integer videoNum; + + /** + * 总阅读量-视频 + */ + private Integer videoReadNum; + + /** + * 总收藏量-视频 + */ + private Integer videoCollectNum; + + /** + * 总评论量-视频 + */ + private Integer videoCommentNum; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalHospitalEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalHospitalEntity.java new file mode 100644 index 0000000..395c419 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalHospitalEntity.java @@ -0,0 +1,86 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-临床-医院 实体类 + * + * @Author xing + * @Date 2025-08-06 17:01:19 + * @Copyright gdxz + */ + +@Data +@TableName("stats_case_clinical_hospital") +public class StatsCaseClinicalHospitalEntity { + + /** + * 主键id + */ + @TableId + private Long statsId; + + /** + * 医院id + */ + private Long hospitalId; + + /** + * 数量-文章 + */ + private Integer articleNum; + + /** + * 总阅读量-文章 + */ + private Integer articleReadNum; + + /** + * 总收藏量-文章 + */ + private Integer articleCollectNum; + + /** + * 总评论量-文章 + */ + private Integer articleCommentNum; + + /** + * 最后一篇文章发表时间 + */ + private LocalDateTime lastPushDate; + + /** + * 数量-视频 + */ + private Integer videoNum; + + /** + * 总阅读量-视频 + */ + private Integer videoReadNum; + + /** + * 总收藏量-视频 + */ + private Integer videoCollectNum; + + /** + * 总评论量-视频 + */ + private Integer videoCommentNum; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalLabelEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalLabelEntity.java new file mode 100644 index 0000000..7c30e8b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/entity/StatsCaseClinicalLabelEntity.java @@ -0,0 +1,91 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-临床-疾病标签 实体类 + * + * @Author xing + * @Date 2025-08-07 09:10:35 + * @Copyright gdxz + */ + +@Data +@TableName("stats_case_clinical_label") +public class StatsCaseClinicalLabelEntity { + + /** + * 主键id + */ + @TableId + private Long statsId; + + /** + * 疾病标签唯一标识 + */ + private String labelIden; + + /** + * 疾病标签名称 + */ + private String labelName; + + /** + * 数量-文章 + */ + private Integer articleNum; + + /** + * 总阅读量-文章 + */ + private Integer articleReadNum; + + /** + * 总收藏量-文章 + */ + private Integer articleCollectNum; + + /** + * 总评论量-文章 + */ + private Integer articleCommentNum; + + /** + * 最后一篇文章发表时间 + */ + private LocalDateTime lastPushDate; + + /** + * 数量-视频 + */ + private Integer videoNum; + + /** + * 总阅读量-视频 + */ + private Integer videoReadNum; + + /** + * 总收藏量-视频 + */ + private Integer videoCollectNum; + + /** + * 总评论量-视频 + */ + private Integer videoCommentNum; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/form/StatsCaseClinicalQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/form/StatsCaseClinicalQueryForm.java new file mode 100644 index 0000000..ff67c22 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/form/StatsCaseClinicalQueryForm.java @@ -0,0 +1,19 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 统计表-病例库-临床 分页查询表单 + * + * @Author xing + * @Date 2025-08-06 08:51:26 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class StatsCaseClinicalQueryForm extends PageParam { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalDoctorVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalDoctorVO.java new file mode 100644 index 0000000..26208cc --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalDoctorVO.java @@ -0,0 +1,58 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-临床-医生 列表VO + * + * @Author xing + * @Date 2025-08-06 09:07:32 + * @Copyright gdxz + */ + +@Data +public class StatsCaseClinicalDoctorVO { + + + @Schema(description = "主键id") + private Long statsId; + + @Schema(description = "医生id") + private Long doctorId; + + @Schema(description = "数量-文章") + private Integer articleNum; + + @Schema(description = "总阅读量-文章") + private Integer articleReadNum; + + @Schema(description = "总收藏量-文章") + private Integer articleCollectNum; + + @Schema(description = "总评论量-文章") + private Integer articleCommentNum; + + @Schema(description = "最后一篇文章发表时间") + private LocalDateTime lastPushDate; + + @Schema(description = "数量-视频") + private Integer videoNum; + + @Schema(description = "总阅读量-视频") + private Integer videoReadNum; + + @Schema(description = "总收藏量-视频") + private Integer videoCollectNum; + + @Schema(description = "总评论量-视频") + private Integer videoCommentNum; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalHospitalVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalHospitalVO.java new file mode 100644 index 0000000..02d6778 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalHospitalVO.java @@ -0,0 +1,58 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-临床-医院 列表VO + * + * @Author xing + * @Date 2025-08-06 17:01:19 + * @Copyright gdxz + */ + +@Data +public class StatsCaseClinicalHospitalVO { + + + @Schema(description = "主键id") + private Long statsId; + + @Schema(description = "医院id") + private Long hospitalId; + + @Schema(description = "数量-文章") + private Integer articleNum; + + @Schema(description = "总阅读量-文章") + private Integer articleReadNum; + + @Schema(description = "总收藏量-文章") + private Integer articleCollectNum; + + @Schema(description = "总评论量-文章") + private Integer articleCommentNum; + + @Schema(description = "最后一篇文章发表时间") + private LocalDateTime lastPushDate; + + @Schema(description = "数量-视频") + private Integer videoNum; + + @Schema(description = "总阅读量-视频") + private Integer videoReadNum; + + @Schema(description = "总收藏量-视频") + private Integer videoCollectNum; + + @Schema(description = "总评论量-视频") + private Integer videoCommentNum; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalLabelVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalLabelVO.java new file mode 100644 index 0000000..500f465 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalLabelVO.java @@ -0,0 +1,61 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-临床-疾病标签 列表VO + * + * @Author xing + * @Date 2025-08-07 09:10:35 + * @Copyright gdxz + */ + +@Data +public class StatsCaseClinicalLabelVO { + + + @Schema(description = "主键id") + private Long statsId; + + @Schema(description = "疾病标签唯一标识") + private String labelIden; + + @Schema(description = "疾病标签名称") + private String labelName; + + @Schema(description = "数量-文章") + private Integer articleNum; + + @Schema(description = "总阅读量-文章") + private Integer articleReadNum; + + @Schema(description = "总收藏量-文章") + private Integer articleCollectNum; + + @Schema(description = "总评论量-文章") + private Integer articleCommentNum; + + @Schema(description = "最后一篇文章发表时间") + private LocalDateTime lastPushDate; + + @Schema(description = "数量-视频") + private Integer videoNum; + + @Schema(description = "总阅读量-视频") + private Integer videoReadNum; + + @Schema(description = "总收藏量-视频") + private Integer videoCollectNum; + + @Schema(description = "总评论量-视频") + private Integer videoCommentNum; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalVO.java new file mode 100644 index 0000000..ef9d956 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/domain/vo/StatsCaseClinicalVO.java @@ -0,0 +1,52 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 统计表-病例库-临床 列表VO + * + * @Author xing + * @Date 2025-08-06 08:51:26 + * @Copyright gdxz + */ + +@Data +public class StatsCaseClinicalVO { + + + @Schema(description = "主键id") + private Long statsId; + + @Schema(description = "数量-文章") + private Integer articleNum; + + @Schema(description = "总阅读量-文章") + private Integer articleReadNum; + + @Schema(description = "总收藏量-文章") + private Integer articleCollectNum; + + @Schema(description = "总评论量-文章") + private Integer articleCommentNum; + + @Schema(description = "数量-视频") + private Integer videoNum; + + @Schema(description = "总阅读量-视频") + private Integer videoReadNum; + + @Schema(description = "总收藏量-视频") + private Integer videoCollectNum; + + @Schema(description = "总评论量-视频") + private Integer videoCommentNum; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalDoctorManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalDoctorManager.java new file mode 100644 index 0000000..ca5fc38 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalDoctorManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.manager; + +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDoctorDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 统计表-病例库-临床-医生 Manager + * + * @Author xing + * @Date 2025-08-06 09:07:32 + * @Copyright gdxz + */ +@Service +public class StatsCaseClinicalDoctorManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalHospitalManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalHospitalManager.java new file mode 100644 index 0000000..7cce749 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalHospitalManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.manager; + +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalHospitalDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalHospitalEntity; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 统计表-病例库-临床-医院 Manager + * + * @Author xing + * @Date 2025-08-06 17:01:19 + * @Copyright gdxz + */ +@Service +public class StatsCaseClinicalHospitalManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalLabelManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalLabelManager.java new file mode 100644 index 0000000..b7f5fa6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalLabelManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.manager; + +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalLabelEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalLabelDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 统计表-病例库-临床-疾病标签 Manager + * + * @Author xing + * @Date 2025-08-07 09:10:35 + * @Copyright gdxz + */ +@Service +public class StatsCaseClinicalLabelManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalManager.java new file mode 100644 index 0000000..b2035f9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/manager/StatsCaseClinicalManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.manager; + +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDao; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 统计表-病例库-临床 Manager + * + * @Author xing + * @Date 2025-08-06 08:51:26 + * @Copyright gdxz + */ +@Service +public class StatsCaseClinicalManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalDoctorService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalDoctorService.java new file mode 100644 index 0000000..2b42910 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalDoctorService.java @@ -0,0 +1,34 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDoctorDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalDoctorVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 统计表-病例库-临床-医生 Service + * + * @Author xing + * @Date 2025-08-06 09:07:32 + * @Copyright gdxz + */ + +@Service +public class StatsCaseClinicalDoctorService { + + @Resource + private StatsCaseClinicalDoctorDao statsCaseClinicalDoctorDao; + + + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalHospitalService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalHospitalService.java new file mode 100644 index 0000000..85faa8e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalHospitalService.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalHospitalDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalHospitalEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalHospitalVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 统计表-病例库-临床-医院 Service + * + * @Author xing + * @Date 2025-08-06 17:01:19 + * @Copyright gdxz + */ + +@Service +public class StatsCaseClinicalHospitalService { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalLabelService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalLabelService.java new file mode 100644 index 0000000..399f82f --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalLabelService.java @@ -0,0 +1,32 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalLabelDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalLabelEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalLabelVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 统计表-病例库-临床-疾病标签 Service + * + * @Author xing + * @Date 2025-08-07 09:10:35 + * @Copyright gdxz + */ + +@Service +public class StatsCaseClinicalLabelService { + + @Resource + private StatsCaseClinicalLabelDao statsCaseClinicalLabelDao; + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalService.java new file mode 100644 index 0000000..45f6849 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/statsCaseClinical/service/StatsCaseClinicalService.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.business.statsCaseClinical.service; + +import java.util.List; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.form.StatsCaseClinicalQueryForm; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.vo.StatsCaseClinicalVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; + +/** + * 统计表-病例库-临床 Service + * + * @Author xing + * @Date 2025-08-06 08:51:26 + * @Copyright gdxz + */ + +@Service +public class StatsCaseClinicalService { + + @Resource + private StatsCaseClinicalDao statsCaseClinicalDao; + + /** + * 分页查询 + */ + public PageResult queryPage(StatsCaseClinicalQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = statsCaseClinicalDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/controller/UserController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/controller/UserController.java new file mode 100644 index 0000000..aa8aff4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/controller/UserController.java @@ -0,0 +1,71 @@ +package net.lab1024.sa.admin.module.business.user.controller; + +import net.lab1024.sa.admin.module.business.user.domain.form.UserAddForm; +import net.lab1024.sa.admin.module.business.user.domain.form.UserQueryForm; +import net.lab1024.sa.admin.module.business.user.domain.form.UserUpdateForm; +import net.lab1024.sa.admin.module.business.user.domain.vo.UserVO; +import net.lab1024.sa.admin.module.business.user.service.UserService; +import net.lab1024.sa.base.common.domain.ValidateList; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; + +/** + * 用户管理 Controller + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ + +@RestController +@Tag(name = "用户管理") +public class UserController { + + @Resource + private UserService userService; + + @Operation(summary = "分页查询 @author xing") + @PostMapping("/user/queryPage") + @SaCheckPermission("user:query") + public ResponseDTO> queryPage(@RequestBody @Valid UserQueryForm queryForm) { + return ResponseDTO.ok(userService.queryPage(queryForm)); + } + + @Operation(summary = "添加 @author xing") + @PostMapping("/user/add") + @SaCheckPermission("user:add") + public ResponseDTO add(@RequestBody @Valid UserAddForm addForm) { + return userService.add(addForm); + } + + @Operation(summary = "更新 @author xing") + @PostMapping("/user/update") + @SaCheckPermission("user:update") + public ResponseDTO update(@RequestBody @Valid UserUpdateForm updateForm) { + return userService.update(updateForm); + } + + @Operation(summary = "批量删除 @author xing") + @PostMapping("/user/batchDelete") + @SaCheckPermission("user:delete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return userService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author xing") + @GetMapping("/user/delete/{userId}") + @SaCheckPermission("user:delete") + public ResponseDTO batchDelete(@PathVariable Long userId) { + return userService.delete(userId); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/dao/UserDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/dao/UserDao.java new file mode 100644 index 0000000..100d97a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/dao/UserDao.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.business.user.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.business.user.domain.entity.UserEntity; +import net.lab1024.sa.admin.module.business.user.domain.form.UserQueryForm; +import net.lab1024.sa.admin.module.business.user.domain.vo.UserVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 用户管理 Dao + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ + +@Mapper +public interface UserDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") UserQueryForm queryForm); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/entity/UserEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/entity/UserEntity.java new file mode 100644 index 0000000..18baccf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/entity/UserEntity.java @@ -0,0 +1,106 @@ +package net.lab1024.sa.admin.module.business.user.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 用户管理 实体类 + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ + +@Data +@TableName("user") +public class UserEntity { + + /** + * 主键id + */ + @TableId + private Long userId; + + /** + * 第三方平台唯一标识 + */ + private String userIden; + + /** + * 用户名称 + */ + private String userName; + + /** + * 手机号(第三方平台时可能为空) + */ + private String userMobile; + + /** + * 手机号加密 + */ + private String mobileEncryption; + + /** + * 状态(0:禁用 1:正常 2:删除) + */ + private Integer status; + + /** + * 注册来源(1:未知 2:app用户 3:佳动例) + */ + private Integer registerSource; + + /** + * 用户微信标识 + */ + private String openId; + + /** + * 微信开放平台标识 + */ + private String unionId; + + /** + * 性别(0:未知 1:男 2:女) + */ + private Integer sex; + + /** + * 头像 + */ + private String avatar; + + /** + * 医生职称(0:未知 1:主任医师 2:主任中医师 3:副主任医师 4:副主任中医师 5:主治医师 6:住院医师) + */ + private Integer title; + + /** + * 科室名称 + */ + private String departmentName; + + /** + * 所属医院id + */ + private Long hospitalId; + + /** + * 医生地址 + */ + private String address; + + /** + * 创建时间 + */ + private LocalDateTime createdAt; + + /** + * 修改时间 + */ + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserAddForm.java new file mode 100644 index 0000000..e126451 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserAddForm.java @@ -0,0 +1,27 @@ +package net.lab1024.sa.admin.module.business.user.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 用户管理 新建表单 + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ + +@Data +public class UserAddForm { + + @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "主键id 不能为空") + private Long userId; + + @Schema(description = "第三方平台唯一标识", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "第三方平台唯一标识 不能为空") + private String userIden; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserQueryForm.java new file mode 100644 index 0000000..d7bc033 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserQueryForm.java @@ -0,0 +1,26 @@ +package net.lab1024.sa.admin.module.business.user.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户管理 分页查询表单 + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ + +@Data +@EqualsAndHashCode(callSuper = false) +public class UserQueryForm extends PageParam { + + @Schema(description = "用户名-手机号") + private String keywords; + + @Schema(description = "状态") + private Integer status; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserUpdateForm.java new file mode 100644 index 0000000..c938c9d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/form/UserUpdateForm.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.business.user.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 用户管理 更新表单 + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ + +@Data +public class UserUpdateForm { + + @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "主键id 不能为空") + private Long userId; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/vo/UserVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/vo/UserVO.java new file mode 100644 index 0000000..d27977a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/domain/vo/UserVO.java @@ -0,0 +1,70 @@ +package net.lab1024.sa.admin.module.business.user.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 用户管理 列表VO + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ + +@Data +public class UserVO { + + + @Schema(description = "主键id") + private Long userId; + + @Schema(description = "第三方平台唯一标识") + private String userIden; + + @Schema(description = "用户名称") + private String userName; + + @Schema(description = "手机号(第三方平台时可能为空)") + private String userMobile; + + @Schema(description = "手机号加密") + private String mobileEncryption; + + @Schema(description = "状态(0:禁用 1:正常 2:删除)") + private Integer status; + + @Schema(description = "注册来源(1:未知 2:app用户 3:佳动例)") + private Integer registerSource; + + @Schema(description = "用户微信标识") + private String openId; + + @Schema(description = "微信开放平台标识") + private String unionId; + + @Schema(description = "性别(0:未知 1:男 2:女)") + private Integer sex; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "医生职称(0:未知 1:主任医师 2:主任中医师 3:副主任医师 4:副主任中医师 5:主治医师 6:住院医师)") + private Integer title; + + @Schema(description = "科室名称") + private String departmentName; + + @Schema(description = "所属医院id") + private Long hospitalId; + + @Schema(description = "医生地址") + private String address; + + @Schema(description = "创建时间") + private LocalDateTime createdAt; + + @Schema(description = "修改时间") + private LocalDateTime updatedAt; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/manager/UserManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/manager/UserManager.java new file mode 100644 index 0000000..a7caa7e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/manager/UserManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.business.user.manager; + +import net.lab1024.sa.admin.module.business.user.dao.UserDao; +import net.lab1024.sa.admin.module.business.user.domain.entity.UserEntity; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 用户管理 Manager + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ +@Service +public class UserManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/service/CertService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/service/CertService.java new file mode 100644 index 0000000..cd23511 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/service/CertService.java @@ -0,0 +1,279 @@ +package net.lab1024.sa.admin.module.business.user.service; + +import net.lab1024.sa.admin.config.EnvConfig; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.admin.extend.aliyun.Oss; +import jakarta.annotation.Resource; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Service; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Objects; + +@Service +public class CertService { + @Resource + private EnvConfig envConfig; + + // 生成证书 + public String createCert( byte[] avatarPath, + String sealPath, + String certificateNo, + String name, + String content, + byte[] qrCodeByte, + String doctorId + ){ + try { + // 加载背景模板图片 + BufferedImage background = ImageIO.read(new ClassPathResource("static/cert/template.png").getInputStream()); + + Graphics2D g2d = (Graphics2D) background.getGraphics(); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // 1. 添加证书编号 + Font font = loadFont("static/cert/msyh.ttf", 40f); +// Font font = new Font("Microsoft YaHei", Font.PLAIN, 40); // 可根据模板调整大小 + g2d.setFont(font); + + Color customColor = Color.decode("#008983"); + g2d.setColor(customColor); + g2d.drawString("证书编号:" + certificateNo, 260, 570); + + // 2. 处理并添加头像 + BufferedImage avatar = ImageIO.read(new ByteArrayInputStream(avatarPath)); + int size = 116; // 目标大小 + BufferedImage circleAvatar = createCircularImage(avatar, size); + g2d.drawImage(circleAvatar, 465, 620, null); + + // 3. 添加姓名 + font = loadFont("static/cert/msyh.ttf", 40f); +// font = new Font("Microsoft YaHei", Font.PLAIN, 40); // 可根据模板调整大小 + g2d.setFont(font); + + customColor = Color.decode("#111827"); + g2d.setColor(customColor); + g2d.drawString(name, 465, 790); + + // 4. 添加证书内容 +// font = new Font("Microsoft YaHei", Font.PLAIN, 48); // 可根据模板调整大小 + font = loadFont("static/cert/msyh.ttf", 48f); + g2d.setFont(font); + + customColor = Color.decode("#111827"); + g2d.setColor(customColor); + drawStringWithLineBreak(g2d, content, 185, 880, 700, font); // 自动换行绘制文本 + + // 5. 添加日期 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); + String currentDate = sdf.format(new Date()); + +// font = new Font("Microsoft YaHei", Font.PLAIN, 34); // 可根据模板调整大小 + font = loadFont("static/cert/msyh.ttf", 34f); + g2d.setFont(font); + + customColor = Color.decode("#111827"); + g2d.setColor(customColor); + g2d.drawString(currentDate, 700, 1277); + + // 6. 添加印章 + BufferedImage seal = ImageIO.read(new ClassPathResource(sealPath).getInputStream()); + seal = resize(seal, 264, 264); // 调整印章大小 + g2d.drawImage(seal, 645, 1150, null); + + // 6. 添加小程序二维码 + BufferedImage wechatMa = ImageIO.read(new ByteArrayInputStream(qrCodeByte)); + wechatMa = resize(wechatMa, 205, 205); // 调整印章大小 + g2d.drawImage(wechatMa, 80, 1450, null); + + // 释放资源 + g2d.dispose(); + + // === 将图片转为 byte[] === + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageIO.write(background, "png", os); + byte[] imageBytes = os.toByteArray(); + + String fileName = ""; + if (Objects.equals(envConfig.getActive(), "dev")){ + fileName = "dev/static/images/" + certificateNo + doctorId + ".png"; + }else{ + fileName = "prod/static/images/" + certificateNo + doctorId + ".png"; + } + + boolean uploaded = Oss.putObject(fileName, imageBytes); + if (uploaded) { + // 返回可访问的 URL(假设你有自定义域名) + // 格式:http://你的域名/文件名 + return "/" + fileName; + } + +// // 保存最终的证书图片 +// ImageIO.write(background, "png", new File("cert.png")); +// System.out.println("Certificate generated successfully!"); + } catch (IOException e) { + throw new BusinessException(e.getMessage()); + } + + return null; + } + + // 生成证书 + public String createCertTest( + String sealPath, + String certificateNo, + String name, + String content + ){ + try { + // 加载背景模板图片 + BufferedImage background = ImageIO.read(new File("src/main/resources/static/cert/template.png")); + + Graphics2D g2d = (Graphics2D) background.getGraphics(); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + + // 1. 添加证书编号 + Font font = new Font("Microsoft YaHei", Font.PLAIN, 40); // 可根据模板调整大小 + g2d.setFont(font); + + Color customColor = Color.decode("#008983"); + g2d.setColor(customColor); + g2d.drawString(certificateNo, 285, 570); + + // 2. 处理并添加头像 + BufferedImage avatar = ImageIO.read(new File("src/main/resources/static/cert/avt.png")); + int size = 116; // 目标大小 + BufferedImage circleAvatar = createCircularImage(avatar, size); + g2d.drawImage(circleAvatar, 465, 620, null); + + // 3. 添加姓名 + font = new Font("Microsoft YaHei", Font.PLAIN, 40); // 可根据模板调整大小 + g2d.setFont(font); + + customColor = Color.decode("#111827"); + g2d.setColor(customColor); + g2d.drawString(name, 465, 790); + + // 4. 添加证书内容 + font = new Font("Microsoft YaHei", Font.PLAIN, 48); // 可根据模板调整大小 + g2d.setFont(font); + + customColor = Color.decode("#111827"); + g2d.setColor(customColor); + drawStringWithLineBreak(g2d, content, 185, 880, 700, font); // 自动换行绘制文本 + + // 5. 添加日期 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); + String currentDate = sdf.format(new Date()); + + font = new Font("Microsoft YaHei", Font.PLAIN, 34); // 可根据模板调整大小 + g2d.setFont(font); + + customColor = Color.decode("#111827"); + g2d.setColor(customColor); + g2d.drawString(currentDate, 700, 1277); + + // 6. 添加印章 + BufferedImage seal = ImageIO.read(new File(sealPath)); + seal = resize(seal, 264, 264); // 调整印章大小 + g2d.drawImage(seal, 645, 1150, null); + + // 6. 添加小程序二维码 + BufferedImage wechatMa = ImageIO.read(new File("src/main/resources/static/cert/weChatMa.png")); + wechatMa = resize(wechatMa, 205, 205); // 调整印章大小 + g2d.drawImage(wechatMa, 80, 1450, null); + + // 释放资源 + g2d.dispose(); + + // === 将图片转为 byte[] === +// ByteArrayOutputStream os = new ByteArrayOutputStream(); +// ImageIO.write(background, "png", os); +// byte[] imageBytes = os.toByteArray(); +// +// String fileName = ""; +// if (Objects.equals(envConfig.getActive(), "dev")){ +// fileName = "dev/static/images/" + certificateNo + ".png"; +// }else{ +// fileName = "prod/static/images/" + certificateNo + ".png"; +// } +// +// boolean uploaded = Oss.putObject(fileName, imageBytes); +// if (uploaded) { +// // 返回可访问的 URL(假设你有自定义域名) +// // 格式:http://你的域名/文件名 +// return "/" + fileName; +// } + +// // 保存最终的证书图片 + ImageIO.write(background, "png", new File("cert.png")); + System.out.println("Certificate generated successfully!"); + } catch (IOException e) { + throw new BusinessException(e.getMessage()); + } + + return null; + } + + private static BufferedImage createCircularImage(BufferedImage originalImg, int size) { + BufferedImage outputImage = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = outputImage.createGraphics(); + g2.setComposite(AlphaComposite.Src); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setColor(Color.WHITE); + g2.fill(new Ellipse2D.Float(0, 0, size, size)); + g2.setComposite(AlphaComposite.SrcAtop); + g2.drawImage(originalImg.getScaledInstance(size, size, Image.SCALE_SMOOTH), 0, 0, null); + g2.dispose(); + return outputImage; + } + + private static BufferedImage resize(BufferedImage img, int newW, int newH) { + Image tmp = img.getScaledInstance(newW, newH, Image.SCALE_SMOOTH); + BufferedImage dimg = new BufferedImage(newW, newH, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = dimg.createGraphics(); + g2d.drawImage(tmp, 0, 0, null); + g2d.dispose(); + return dimg; + } + + // 绘制带自动换行的字符串 + private static void drawStringWithLineBreak(Graphics2D g2d, String text, int x, int y, int maxWidth, Font font) { + FontMetrics fm = g2d.getFontMetrics(font); + StringBuilder line = new StringBuilder(); + String[] words = text.split(""); + + for (String word : words) { + int lineWidth = fm.stringWidth(line + word); + if (lineWidth < maxWidth) { + line.append(word); + } else { + g2d.drawString(line.toString(), x, y); + y += fm.getHeight(); + line = new StringBuilder(word); + } + } + if (!line.isEmpty()) { + g2d.drawString(line.toString(), x, y); + } + } + + public static Font loadFont(String path, float size) { + try { + ClassPathResource resource = new ClassPathResource(path); + try (InputStream inputStream = resource.getInputStream()) { + return Font.createFont(Font.TRUETYPE_FONT, inputStream).deriveFont(size); + } + } catch (Exception e) { + throw new RuntimeException("字体加载失败: " + path, e); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/service/UserService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/service/UserService.java new file mode 100644 index 0000000..0ed3fe7 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/business/user/service/UserService.java @@ -0,0 +1,279 @@ +package net.lab1024.sa.admin.module.business.user.service; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.time.LocalDateTime; +import java.time.Year; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Objects; +import java.util.Random; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import net.lab1024.sa.admin.config.EnvConfig; +import net.lab1024.sa.admin.extend.aliyun.Oss; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.dao.CaseClinicalArticleDao; +import net.lab1024.sa.admin.module.business.caseClinicalArticle.domain.entity.CaseClinicalArticleEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorCertDao; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.dao.CaseClinicalDoctorDao; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorCertEntity; +import net.lab1024.sa.admin.module.business.caseClinicalDoctor.domain.entity.CaseClinicalDoctorEntity; +import net.lab1024.sa.admin.module.business.statsCaseClinical.dao.StatsCaseClinicalDao; +import net.lab1024.sa.admin.module.business.statsCaseClinical.domain.entity.StatsCaseClinicalEntity; +import net.lab1024.sa.admin.module.business.user.dao.UserDao; +import net.lab1024.sa.admin.module.business.user.domain.entity.UserEntity; +import net.lab1024.sa.admin.module.business.user.domain.form.UserAddForm; +import net.lab1024.sa.admin.module.business.user.domain.form.UserQueryForm; +import net.lab1024.sa.admin.module.business.user.domain.form.UserUpdateForm; +import net.lab1024.sa.admin.module.business.user.domain.vo.UserVO; +import net.lab1024.sa.base.common.exception.BusinessException; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import jakarta.annotation.Resource; +import org.springframework.transaction.annotation.Transactional; + +/** + * 用户管理 Service + * + * @Author xing + * @Date 2025-08-06 11:07:39 + * @Copyright gdxz + */ + +@Service +public class UserService { + + @Resource + private UserDao userDao; + + @Resource + private CaseClinicalArticleDao caseClinicalArticleDao; + + @Resource + private CaseClinicalDoctorDao caseClinicalDoctorDao; + + @Resource + private CaseClinicalDoctorCertDao caseClinicalDoctorCertDao; + + @Resource + private StatsCaseClinicalDao statsCaseClinicalDao; + + @Resource + private CertService certService; + + @Resource + private EnvConfig envConfig; + + /** + * 分页查询 + */ + public PageResult queryPage(UserQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = userDao.queryPage(page, queryForm); + return SmartPageUtil.convert2PageResult(page, list); + } + + /** + * 添加 + */ + public ResponseDTO add(UserAddForm addForm) { + UserEntity userEntity = SmartBeanUtil.copy(addForm, UserEntity.class); + userDao.insert(userEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + */ + public ResponseDTO update(UserUpdateForm updateForm) { + UserEntity userEntity = SmartBeanUtil.copy(updateForm, UserEntity.class); + userDao.updateById(userEntity); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + */ + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)){ + return ResponseDTO.ok(); + } + + userDao.deleteBatchIds(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + */ + public ResponseDTO delete(Long userId) { + if (null == userId){ + return ResponseDTO.ok(); + } + + userDao.deleteById(userId); + return ResponseDTO.ok(); + } + + /** + * 生成用户证书-文章/视频 + * @param id 文章/视频id + * @param type 类型 1:文章 2:视频 + */ + @Transactional + public boolean CreateUserCert(String id,Integer type,String doctorId, byte[] qrCodeByte, byte[] avatarByte) throws BusinessException { + try { + String title = ""; // 标题 + + if (type == 1){ + // 获取文章数据 + CaseClinicalArticleEntity caseClinicalArticle = caseClinicalArticleDao.selectById(Long.valueOf(id)); + if (caseClinicalArticle == null){ + throw new BusinessException("生成证书错误"); + } + + title = caseClinicalArticle.getArticleTitle(); + + }else if (type == 2){ +// CaseClinicalVideoEntity caseClinicalVideo = caseClinicalVideoDao.selectById(Long.valueOf(id)); +// +// if (caseClinicalVideo == null){ +// throw new BusinessException("生成证书错误"); +// } +// +// title = caseClinicalVideo.getVideoTitle(); + + }else{ + throw new BusinessException("生成证书错误"); + } + + // 获取医生数据 + CaseClinicalDoctorEntity caseClinicalDoctor = caseClinicalDoctorDao.selectById(doctorId); + if (caseClinicalDoctor == null){ + throw new BusinessException("生成证书错误"); + } + + // 获取证书文件 + LambdaQueryWrapper certWrapper = new LambdaQueryWrapper<>(); + certWrapper.eq(CaseClinicalDoctorCertEntity::getDoctorId, doctorId); + certWrapper.eq(CaseClinicalDoctorCertEntity::getId, id); + certWrapper.eq(CaseClinicalDoctorCertEntity::getType, type); + CaseClinicalDoctorCertEntity caseClinicalDoctorCert = caseClinicalDoctorCertDao.selectOne(certWrapper); + if (caseClinicalDoctorCert != null){ + return true; + } + + // 获取统计数据 + StatsCaseClinicalEntity statsCaseClinical = statsCaseClinicalDao.selectById(1); + if (statsCaseClinical == null){ + throw new BusinessException("生成证书错误"); + } + + // 生成证书 + String certificateNo = "GDXZALK" + + String.valueOf(Year.now().getValue()) + + String.format("%06d", (statsCaseClinical.getArticleNum() + statsCaseClinical.getVideoNum())); + + String ossPath = certService.createCert( + avatarByte, + "static/cert/seal.png", + certificateNo, + caseClinicalDoctor.getDoctorName(), + "您的案例《" + title + "》经评议,被肝胆相照临床病例库收录,特发此证。", + qrCodeByte, + doctorId + ); + + // 新增证书文件 + caseClinicalDoctorCert = new CaseClinicalDoctorCertEntity(); + caseClinicalDoctorCert.setDoctorId(Long.valueOf(doctorId)); + caseClinicalDoctorCert.setId(Long.valueOf(id)); + caseClinicalDoctorCert.setType(type); + caseClinicalDoctorCert.setCertImage(ossPath); + caseClinicalDoctorCertDao.insert(caseClinicalDoctorCert); + + return true; + } catch (Exception e) { + throw new BusinessException(e.getMessage()); + } + } + + /** + * 处理用户头像:下载远程头像并上传至 OSS + * + * @param wxAvatarUrl 微信头像地址 + * @return OSS 路径(以 / 开头),如 /user/avatar/202507301530123456.png + */ + public String handleUserImage(String wxAvatarUrl) { + if (wxAvatarUrl == null || wxAvatarUrl.isEmpty()) { + return null; + } + + HttpURLConnection conn = null; + try { + // 1. 下载远程图片 + URL url = new URL(wxAvatarUrl); + conn = (HttpURLConnection) url.openConnection(); + conn.setConnectTimeout(5000); + conn.setReadTimeout(10000); + conn.setRequestMethod("GET"); + + if (conn.getResponseCode() != 200) { + throw new BusinessException("图片处理失败"); + } + + try (InputStream input = conn.getInputStream(); + ByteArrayOutputStream output = new ByteArrayOutputStream()) { + + byte[] buffer = new byte[4096]; + int len; + while ((len = input.read(buffer)) != -1) { + output.write(buffer, 0, len); + } + + byte[] imageBytes = output.toByteArray(); + if (imageBytes.length == 0) { + throw new BusinessException("图片处理失败"); + } + + // 2. 生成 OSS 路径 + String dateTimeStr = LocalDateTime.now() + .format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); + int randomSuffix = new Random().nextInt(9000) + 1000; + + String ossPath = ""; + if (Objects.equals(envConfig.getActive(), "dev")){ + ossPath = "dev/static/images/" + dateTimeStr + randomSuffix + ".png"; + }else{ + ossPath = "prod/static/images/" + dateTimeStr + randomSuffix + ".png"; + } + + // 3. 上传 OSS + boolean success = Oss.putObject(ossPath, imageBytes); + if (!success) { + throw new BusinessException("图片处理失败"); + } + + return "/" + ossPath; + } + + } catch (Exception e) { + // 头像处理失败 + System.out.println(e.getMessage()); + return ""; + } finally { + if (conn != null) { + conn.disconnect(); + } + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/DataScope.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/DataScope.java new file mode 100644 index 0000000..3f7307d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/DataScope.java @@ -0,0 +1,50 @@ +package net.lab1024.sa.admin.module.system.datascope; + + +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeWhereInTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.strategy.AbstractDataScopeStrategy; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 数据范围 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-03-18 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface DataScope { + + DataScopeTypeEnum dataScopeType() ; + + DataScopeWhereInTypeEnum whereInType() default DataScopeWhereInTypeEnum.EMPLOYEE; + + /** + * DataScopeWhereInTypeEnum.CUSTOM_STRATEGY类型 才可使用joinSqlImplClazz属性 + */ + Class joinSqlImplClazz() default AbstractDataScopeStrategy.class; + + /** + * 多个参数已逗号分隔,本属性主要用于joinSqlImplClazz 实现类跟进参数进行不同的范围控制,如不使用CUSTOM_STRATEGY,可不做配置 + */ + String paramName() default ""; + /** + * + * 第几个where 条件 从0开始 + */ + int whereIndex() default 0; + + /** + * DataScopeWhereInTypeEnum为CUSTOM_STRATEGY类型时,此属性无效 + */ + String joinSql() default ""; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/DataScopeController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/DataScopeController.java new file mode 100644 index 0000000..8f2fec8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/DataScopeController.java @@ -0,0 +1,38 @@ +package net.lab1024.sa.admin.module.system.datascope; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.datascope.domain.DataScopeAndViewTypeVO; +import net.lab1024.sa.admin.module.system.datascope.service.DataScopeService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 查询支持的数据范围类型 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-03-18 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_DATA_SCOPE) +public class DataScopeController { + + @Resource + private DataScopeService dataScopeService; + + @Operation(summary = "获取当前系统所配置的所有数据范围 @author 罗伊") + @GetMapping("/dataScope/list") + public ResponseDTO> dataScopeList() { + return dataScopeService.dataScopeList(); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/MyBatisPlugin.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/MyBatisPlugin.java new file mode 100644 index 0000000..76dab10 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/MyBatisPlugin.java @@ -0,0 +1,186 @@ +package net.lab1024.sa.admin.module.system.datascope; + +import cn.hutool.core.util.StrUtil; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.datascope.domain.DataScopeSqlConfig; +import net.lab1024.sa.admin.module.system.datascope.service.DataScopeSqlConfigService; +import net.lab1024.sa.base.common.domain.DataScopePlugin; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.mapping.*; +import org.apache.ibatis.plugin.Intercepts; +import org.apache.ibatis.plugin.Invocation; +import org.apache.ibatis.plugin.Plugin; +import org.apache.ibatis.plugin.Signature; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * mybaits sql 拦截 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-03-18 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Intercepts({@Signature(type = org.apache.ibatis.executor.Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) +@Component +public class MyBatisPlugin extends DataScopePlugin { + + @Resource + private ApplicationContext applicationContext; + + @Override + public Object intercept(Invocation invocation) throws Throwable { + + MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; + Object parameter = invocation.getArgs()[1]; + + BoundSql boundSql = mappedStatement.getBoundSql(parameter); + String originalSql = boundSql.getSql().trim(); + String id = mappedStatement.getId(); + List methodStrList = StrUtil.split(id, "."); + String path = methodStrList.get(methodStrList.size() - 2) + "." + methodStrList.get(methodStrList.size() - 1); + DataScopeSqlConfigService dataScopeSqlConfigService = this.dataScopeSqlConfigService(); + if (dataScopeSqlConfigService == null) { + return invocation.proceed(); + } + DataScopeSqlConfig sqlConfigDTO = dataScopeSqlConfigService.getSqlConfig(path); + if (sqlConfigDTO != null) { + Map paramMap = this.getParamList(sqlConfigDTO.getParamName(), parameter); + BoundSql newBoundSql = copyFromBoundSql(mappedStatement, boundSql, this.joinSql(originalSql, paramMap, sqlConfigDTO)); + ParameterMap map = mappedStatement.getParameterMap(); + MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql), map); + invocation.getArgs()[0] = newMs; + } + + Object obj = invocation.proceed(); + return obj; + } + + + private Map getParamList(String paramName, Object parameter) { + Map paramMap = Maps.newHashMap(); + if (StringUtils.isEmpty(paramName)) { + return paramMap; + } + if (parameter == null) { + return paramMap; + } + if (parameter instanceof Map) { + String[] paramNameArray = paramName.split(","); + Map parameterMap = (Map) parameter; + for (String param : paramNameArray) { + if(parameterMap.containsKey(param)){ + paramMap.put(param, parameterMap.get(param)); + } + } + } + return paramMap; + } + + private String joinSql(String sql, Map paramMap, DataScopeSqlConfig sqlConfigDTO) { + if (null == sqlConfigDTO) { + return sql; + } + String appendSql = this.dataScopeSqlConfigService().getJoinSql(paramMap, sqlConfigDTO); + if (StringUtils.isEmpty(appendSql)) { + return sql; + } + Integer appendSqlWhereIndex = sqlConfigDTO.getWhereIndex(); + String where = "where"; + String order = "order by"; + String group = "group by"; + int whereIndex = StringUtils.ordinalIndexOf(sql.toLowerCase(), where, appendSqlWhereIndex + 1); + int orderIndex = sql.toLowerCase().indexOf(order); + int groupIndex = sql.toLowerCase().indexOf(group); + if (whereIndex > -1) { + String subSql = sql.substring(0, whereIndex + where.length() + 1); + subSql = subSql + " " + appendSql + " AND " + sql.substring(whereIndex + where.length() + 1); + return subSql; + } + + if (groupIndex > -1) { + String subSql = sql.substring(0, groupIndex); + subSql = subSql + " where " + appendSql + " " + sql.substring(groupIndex); + return subSql; + } + if (orderIndex > -1) { + String subSql = sql.substring(0, orderIndex); + subSql = subSql + " where " + appendSql + " " + sql.substring(orderIndex); + return subSql; + } + sql += " where " + appendSql; + return sql; + } + + public DataScopeSqlConfigService dataScopeSqlConfigService() { + return (DataScopeSqlConfigService) applicationContext.getBean("dataScopeSqlConfigService"); + } + + public class BoundSqlSqlSource implements SqlSource { + + BoundSql boundSql; + + public BoundSqlSqlSource(BoundSql boundSql) { + this.boundSql = boundSql; + } + + @Override + public BoundSql getBoundSql(Object parameterObject) { + return boundSql; + } + } + + /** + * 复制MappedStatement对象 + */ + private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource, ParameterMap parameterMap) { + + MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType()); + builder.resource(ms.getResource()); + builder.fetchSize(ms.getFetchSize()); + builder.statementType(ms.getStatementType()); + builder.keyGenerator(ms.getKeyGenerator()); + builder.timeout(ms.getTimeout()); + builder.parameterMap(parameterMap); + builder.resultMaps(ms.getResultMaps()); + builder.resultSetType(ms.getResultSetType()); + builder.cache(ms.getCache()); + builder.flushCacheRequired(ms.isFlushCacheRequired()); + builder.useCache(ms.isUseCache()); + return builder.build(); + } + + /** + * 复制BoundSql对象 + */ + private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) { + BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject()); + for (ParameterMapping mapping : boundSql.getParameterMappings()) { + String prop = mapping.getProperty(); + if (boundSql.hasAdditionalParameter(prop)) { + newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop)); + } + } + return newBoundSql; + } + + @Override + public Object plugin(Object arg0) { + return Plugin.wrap(arg0, this); + } + + @Override + public void setProperties(Properties arg0) { + + } + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeTypeEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeTypeEnum.java new file mode 100644 index 0000000..130d817 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeTypeEnum.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.admin.module.system.datascope.constant; + +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 数据范围 类型 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public enum DataScopeTypeEnum implements BaseEnum { + + /** + * 系统通知 + */ + NOTICE(1, 20, "系统通知", "系统通知数据范围"), + ; + + private final Integer value; + + private final Integer sort; + + private final String name; + + private final String desc; + + DataScopeTypeEnum(Integer value, Integer sort, String name, String desc) { + this.value = value; + this.sort = sort; + this.name = name; + this.desc = desc; + } + + @Override + public Integer getValue() { + return value; + } + + public Integer getSort() { + return sort; + } + + @Override + public String getDesc() { + return desc; + } + + public String getName() { + return name; + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeViewTypeEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeViewTypeEnum.java new file mode 100644 index 0000000..2350e2c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeViewTypeEnum.java @@ -0,0 +1,65 @@ +package net.lab1024.sa.admin.module.system.datascope.constant; + + +import net.lab1024.sa.base.common.enumeration.BaseEnum; + + +/** + * 数据可见范围类型 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public enum DataScopeViewTypeEnum implements BaseEnum { + + /** + * 本人 + */ + ME(0, 0, "本人"), + + /** + * 部门 + */ + DEPARTMENT(1, 5, "本部门"), + + /** + * 本部门及下属子部门 + */ + DEPARTMENT_AND_SUB(2, 10, "本部门及下属子部门"), + + /** + * 全部 + */ + ALL(10, 100, "全部"); + + + + private final Integer value; + private final Integer level; + private final String desc; + + DataScopeViewTypeEnum(Integer value, Integer level, String desc) { + this.value = value; + this.level = level; + this.desc = desc; + } + + @Override + public Integer getValue() { + return value; + } + + public Integer getLevel() { + return level; + } + + @Override + public String getDesc() { + return desc; + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeWhereInTypeEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeWhereInTypeEnum.java new file mode 100644 index 0000000..9692a4a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/constant/DataScopeWhereInTypeEnum.java @@ -0,0 +1,51 @@ +package net.lab1024.sa.admin.module.system.datascope.constant; + + +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 数据范围 sql where + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public enum DataScopeWhereInTypeEnum implements BaseEnum { + + /** + * 以员工IN + */ + EMPLOYEE(0, "以员工IN"), + + /** + * 以部门IN + */ + DEPARTMENT(1, "以部门IN"), + + /** + * 自定义策略 + */ + CUSTOM_STRATEGY(2, "自定义策略"); + + private final Integer value; + private final String desc; + + DataScopeWhereInTypeEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + @Override + public Integer getValue() { + return value; + } + + @Override + public String getDesc() { + return desc; + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeAndViewTypeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeAndViewTypeVO.java new file mode 100644 index 0000000..5787f79 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeAndViewTypeVO.java @@ -0,0 +1,35 @@ +package net.lab1024.sa.admin.module.system.datascope.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 数据范围 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class DataScopeAndViewTypeVO { + + @Schema(description = "数据范围类型") + private Integer dataScopeType; + + @Schema(description = "数据范围名称") + private String dataScopeTypeName; + + @Schema(description = "描述") + private String dataScopeTypeDesc; + + @Schema(description = "顺序") + private Integer dataScopeTypeSort; + + @Schema(description = "可见范围列表") + private List viewTypeList; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeDTO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeDTO.java new file mode 100644 index 0000000..b0c7ad9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeDTO.java @@ -0,0 +1,32 @@ +package net.lab1024.sa.admin.module.system.datascope.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +/** + * 数据范围 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@Builder +public class DataScopeDTO { + + @Schema(description = "数据范围类型") + private Integer dataScopeType; + + @Schema(description = "数据范围名称") + private String dataScopeTypeName; + + @Schema(description = "描述") + private String dataScopeTypeDesc; + + @Schema(description = "顺序") + private Integer dataScopeTypeSort; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeSqlConfig.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeSqlConfig.java new file mode 100644 index 0000000..3ba5c42 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeSqlConfig.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.admin.module.system.datascope.domain; + +import lombok.Data; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeWhereInTypeEnum; + +/** + * 数据范围 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class DataScopeSqlConfig { + + /** + * 数据范围类型 + * {@link DataScopeTypeEnum} + */ + private DataScopeTypeEnum dataScopeType; + + /** + * join sql 具体实现类 + */ + private Class joinSqlImplClazz; + + private String joinSql; + + private Integer whereIndex; + + private String paramName; + + /** + * whereIn类型 + * {@link DataScopeWhereInTypeEnum} + */ + private DataScopeWhereInTypeEnum dataScopeWhereInType; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeViewTypeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeViewTypeVO.java new file mode 100644 index 0000000..106a2fc --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/domain/DataScopeViewTypeVO.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.admin.module.system.datascope.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; +import lombok.Data; + +/** + * 数据可见范围 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@Builder +public class DataScopeViewTypeVO { + + @Schema(description = "可见范围") + private Integer viewType; + + @Schema(description = "可见范围名称") + private String viewTypeName; + + @Schema(description = "级别,用于表示范围大小") + private Integer viewTypeLevel; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeService.java new file mode 100644 index 0000000..dbad387 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeService.java @@ -0,0 +1,71 @@ +package net.lab1024.sa.admin.module.system.datascope.service; + +import com.google.common.collect.Lists; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeViewTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.domain.DataScopeAndViewTypeVO; +import net.lab1024.sa.admin.module.system.datascope.domain.DataScopeDTO; +import net.lab1024.sa.admin.module.system.datascope.domain.DataScopeViewTypeVO; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.springframework.stereotype.Service; + +import java.util.Comparator; +import java.util.List; + +/** + * 数据范围 保存 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class DataScopeService { + + /** + * 获取所有可以进行数据范围配置的信息 + */ + public ResponseDTO> dataScopeList() { + List dataScopeList = this.getDataScopeType(); + List dataScopeAndTypeList = SmartBeanUtil.copyList(dataScopeList, DataScopeAndViewTypeVO.class); + List typeList = this.getViewType(); + dataScopeAndTypeList.forEach(e -> { + e.setViewTypeList(typeList); + }); + return ResponseDTO.ok(dataScopeAndTypeList); + } + + /** + * 获取当前系统存在的数据可见范围 + */ + public List getViewType() { + List viewTypeList = Lists.newArrayList(); + DataScopeViewTypeEnum[] enums = DataScopeViewTypeEnum.class.getEnumConstants(); + DataScopeViewTypeVO dataScopeViewTypeDTO; + for (DataScopeViewTypeEnum viewTypeEnum : enums) { + dataScopeViewTypeDTO = DataScopeViewTypeVO.builder().viewType(viewTypeEnum.getValue()).viewTypeLevel(viewTypeEnum.getLevel()).viewTypeName(viewTypeEnum.getDesc()).build(); + viewTypeList.add(dataScopeViewTypeDTO); + } + Comparator comparator = (h1, h2) -> h1.getViewTypeLevel().compareTo(h2.getViewTypeLevel()); + viewTypeList.sort(comparator); + return viewTypeList; + } + + public List getDataScopeType() { + List dataScopeTypeList = Lists.newArrayList(); + DataScopeTypeEnum[] enums = DataScopeTypeEnum.class.getEnumConstants(); + DataScopeDTO dataScopeDTO; + for (DataScopeTypeEnum typeEnum : enums) { + dataScopeDTO = + DataScopeDTO.builder().dataScopeType(typeEnum.getValue()).dataScopeTypeDesc(typeEnum.getDesc()).dataScopeTypeName(typeEnum.getName()).dataScopeTypeSort(typeEnum.getSort()).build(); + dataScopeTypeList.add(dataScopeDTO); + } + Comparator comparator = (h1, h2) -> h1.getDataScopeTypeSort().compareTo(h2.getDataScopeTypeSort()); + dataScopeTypeList.sort(comparator); + return dataScopeTypeList; + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeSqlConfigService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeSqlConfigService.java new file mode 100644 index 0000000..493d3b1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeSqlConfigService.java @@ -0,0 +1,149 @@ +package net.lab1024.sa.admin.module.system.datascope.service; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.AdminApplication; +import net.lab1024.sa.admin.module.system.datascope.DataScope; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeViewTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeWhereInTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.domain.DataScopeSqlConfig; +import net.lab1024.sa.admin.module.system.datascope.strategy.AbstractDataScopeStrategy; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.reflections.Reflections; +import org.reflections.scanners.MethodAnnotationsScanner; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * sql配置 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Slf4j +@Service +public class DataScopeSqlConfigService { + + /** + * 注解joinsql 参数 + */ + private static final String EMPLOYEE_PARAM = "#employeeIds"; + + private static final String DEPARTMENT_PARAM = "#departmentIds"; + + /** + * 用于拼接查看本人数据范围的 SQL + */ + private static final String CREATE_USER_ID_EQUALS = "create_user_id = "; + + private final ConcurrentHashMap dataScopeMethodMap = new ConcurrentHashMap<>(); + + @Resource + private DataScopeViewService dataScopeViewService; + + @Resource + private ApplicationContext applicationContext; + + + @PostConstruct + private void initDataScopeMethodMap() { + this.refreshDataScopeMethodMap(); + } + + /** + * 刷新 所有添加数据范围注解的接口方法配置 + */ + private Map refreshDataScopeMethodMap() { + Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(AdminApplication.COMPONENT_SCAN)).setScanners(new MethodAnnotationsScanner())); + Set methods = reflections.getMethodsAnnotatedWith(DataScope.class); + for (Method method : methods) { + DataScope dataScopeAnnotation = method.getAnnotation(DataScope.class); + if (dataScopeAnnotation != null) { + DataScopeSqlConfig configDTO = new DataScopeSqlConfig(); + configDTO.setDataScopeType(dataScopeAnnotation.dataScopeType()); + configDTO.setJoinSql(dataScopeAnnotation.joinSql()); + configDTO.setWhereIndex(dataScopeAnnotation.whereIndex()); + configDTO.setDataScopeWhereInType(dataScopeAnnotation.whereInType()); + configDTO.setParamName(dataScopeAnnotation.paramName()); + configDTO.setJoinSqlImplClazz(dataScopeAnnotation.joinSqlImplClazz()); + dataScopeMethodMap.put(method.getDeclaringClass().getSimpleName() + "." + method.getName(), configDTO); + } + } + return dataScopeMethodMap; + } + + /** + * 根据调用的方法获取,此方法的配置信息 + */ + public DataScopeSqlConfig getSqlConfig(String method) { + return this.dataScopeMethodMap.get(method); + } + + /** + * 组装需要拼接的sql + */ + public String getJoinSql(Map paramMap, DataScopeSqlConfig sqlConfigDTO) { + Long employeeId = SmartRequestUtil.getRequestUserId(); + if (employeeId == null) { + return ""; + } + + DataScopeTypeEnum dataScopeTypeEnum = sqlConfigDTO.getDataScopeType(); + DataScopeViewTypeEnum viewTypeEnum = dataScopeViewService.getEmployeeDataScopeViewType(dataScopeTypeEnum, employeeId); + + // 数据权限设置为仅本人可见时 直接返回 create_user_id = employeeId + if (DataScopeViewTypeEnum.ME == viewTypeEnum) { + return CREATE_USER_ID_EQUALS + employeeId; + } + + String joinSql = sqlConfigDTO.getJoinSql(); + + if (DataScopeWhereInTypeEnum.CUSTOM_STRATEGY == sqlConfigDTO.getDataScopeWhereInType()) { + Class strategyClass = sqlConfigDTO.getJoinSqlImplClazz(); + if (strategyClass == null) { + log.warn("data scope custom strategy class is null"); + return ""; + } + AbstractDataScopeStrategy powerStrategy = (AbstractDataScopeStrategy) applicationContext.getBean(sqlConfigDTO.getJoinSqlImplClazz()); + if (powerStrategy == null) { + log.warn("data scope custom strategy class:{} ,bean is null", sqlConfigDTO.getJoinSqlImplClazz()); + return ""; + } + return powerStrategy.getCondition(viewTypeEnum, paramMap, sqlConfigDTO); + } + if (DataScopeWhereInTypeEnum.EMPLOYEE == sqlConfigDTO.getDataScopeWhereInType()) { + List canViewEmployeeIds = dataScopeViewService.getCanViewEmployeeId(viewTypeEnum, employeeId); + if (CollectionUtils.isEmpty(canViewEmployeeIds)) { + return ""; + } + String employeeIds = StringUtils.join(canViewEmployeeIds, ","); + String sql = joinSql.replaceAll(EMPLOYEE_PARAM, employeeIds); + return sql; + } + if (DataScopeWhereInTypeEnum.DEPARTMENT == sqlConfigDTO.getDataScopeWhereInType()) { + List canViewDepartmentIds = dataScopeViewService.getCanViewDepartmentId(viewTypeEnum, employeeId); + if (CollectionUtils.isEmpty(canViewDepartmentIds)) { + return ""; + } + String departmentIds = StringUtils.join(canViewDepartmentIds, ","); + String sql = joinSql.replaceAll(DEPARTMENT_PARAM, departmentIds); + return sql; + } + return ""; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeViewService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeViewService.java new file mode 100644 index 0000000..1558573 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/service/DataScopeViewService.java @@ -0,0 +1,146 @@ +package net.lab1024.sa.admin.module.system.datascope.service; + +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeViewTypeEnum; +import net.lab1024.sa.admin.module.system.department.service.DepartmentService; +import net.lab1024.sa.admin.module.system.employee.dao.EmployeeDao; +import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; +import net.lab1024.sa.admin.module.system.role.dao.RoleDataScopeDao; +import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleDataScopeEntity; +import net.lab1024.sa.base.common.util.SmartEnumUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 数据范围 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class DataScopeViewService { + + @Resource + private RoleEmployeeDao roleEmployeeDao; + + @Resource + private RoleDataScopeDao roleDataScopeDao; + + @Resource + private EmployeeDao employeeDao; + + @Resource + private DepartmentService departmentService; + + /** + * 获取某人可以查看的所有人员数据 + */ + public List getCanViewEmployeeId(DataScopeViewTypeEnum viewType, Long employeeId) { + if (DataScopeViewTypeEnum.ME == viewType) { + return this.getMeEmployeeIdList(employeeId); + } + if (DataScopeViewTypeEnum.DEPARTMENT == viewType) { + return this.getDepartmentEmployeeIdList(employeeId); + } + if (DataScopeViewTypeEnum.DEPARTMENT_AND_SUB == viewType) { + return this.getDepartmentAndSubEmployeeIdList(employeeId); + } + // 可以查看所有员工数据 + return Lists.newArrayList(); + } + + /** + * 获取某人可以查看的所有部门数据 + */ + public List getCanViewDepartmentId(DataScopeViewTypeEnum viewType, Long employeeId) { + if (DataScopeViewTypeEnum.ME == viewType) { + // 数据可见范围类型为本人时 不可以查看任何部门数据 + return Lists.newArrayList(0L); + } + if (DataScopeViewTypeEnum.DEPARTMENT == viewType) { + return this.getMeDepartmentIdList(employeeId); + } + if (DataScopeViewTypeEnum.DEPARTMENT_AND_SUB == viewType) { + return this.getDepartmentAndSubIdList(employeeId); + } + // 可以查看所有部门数据 + return Lists.newArrayList(); + } + + public List getMeDepartmentIdList(Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + return Lists.newArrayList(employeeEntity.getDepartmentId()); + } + + public List getDepartmentAndSubIdList(Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + return departmentService.selfAndChildrenIdList(employeeEntity.getDepartmentId()); + } + + /** + * 根据员工id 获取各数据范围最大的可见范围 map + */ + public DataScopeViewTypeEnum getEmployeeDataScopeViewType(DataScopeTypeEnum dataScopeTypeEnum, Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (employeeEntity == null || employeeEntity.getEmployeeId() == null) { + return DataScopeViewTypeEnum.ME; + } + + // 如果是超级管理员 则可查看全部 + if (employeeEntity.getAdministratorFlag()) { + return DataScopeViewTypeEnum.ALL; + } + + List roleIdList = roleEmployeeDao.selectRoleIdByEmployeeId(employeeId); + //未设置角色 默认本人 + if (CollectionUtils.isEmpty(roleIdList)) { + return DataScopeViewTypeEnum.ME; + } + //未设置角色数据范围 默认本人 + List dataScopeRoleList = roleDataScopeDao.listByRoleIdList(roleIdList); + if (CollectionUtils.isEmpty(dataScopeRoleList)) { + return DataScopeViewTypeEnum.ME; + } + Map> listMap = dataScopeRoleList.stream().collect(Collectors.groupingBy(RoleDataScopeEntity::getDataScopeType)); + List viewLevelList = listMap.getOrDefault(dataScopeTypeEnum.getValue(), Lists.newArrayList()); + if (CollectionUtils.isEmpty(viewLevelList)) { + return DataScopeViewTypeEnum.ME; + } + RoleDataScopeEntity maxLevel = viewLevelList.stream().max(Comparator.comparing(e -> SmartEnumUtil.getEnumByValue(e.getViewType(), DataScopeViewTypeEnum.class).getLevel())).get(); + return SmartEnumUtil.getEnumByValue(maxLevel.getViewType(), DataScopeViewTypeEnum.class); + } + + /** + * 获取本人相关 可查看员工id + */ + private List getMeEmployeeIdList(Long employeeId) { + return Lists.newArrayList(employeeId); + } + + /** + * 获取本部门相关 可查看员工id + */ + private List getDepartmentEmployeeIdList(Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + return employeeDao.getEmployeeIdByDepartmentId(employeeEntity.getDepartmentId(), false); + } + + /** + * 获取本部门及下属子部门相关 可查看员工id + */ + private List getDepartmentAndSubEmployeeIdList(Long employeeId) { + List allDepartmentIds = getDepartmentAndSubIdList(employeeId); + return employeeDao.getEmployeeIdByDepartmentIdList(allDepartmentIds, false); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/strategy/AbstractDataScopeStrategy.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/strategy/AbstractDataScopeStrategy.java new file mode 100644 index 0000000..152bb1e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/datascope/strategy/AbstractDataScopeStrategy.java @@ -0,0 +1,23 @@ +package net.lab1024.sa.admin.module.system.datascope.strategy; + +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeViewTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.domain.DataScopeSqlConfig; + +import java.util.Map; + +/** + * 数据范围策略 ,使用DataScopeWhereInTypeEnum.CUSTOM_STRATEGY类型,DataScope注解的joinSql属性无用 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2020/11/28 20:59:17 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public abstract class AbstractDataScopeStrategy { + + /** + * 获取joinsql 字符串 + */ + public abstract String getCondition(DataScopeViewTypeEnum viewTypeEnum, Map paramMap, DataScopeSqlConfig sqlConfigDTO); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/controller/DepartmentController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/controller/DepartmentController.java new file mode 100644 index 0000000..2dc9e5c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/controller/DepartmentController.java @@ -0,0 +1,68 @@ +package net.lab1024.sa.admin.module.system.department.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.department.domain.form.DepartmentAddForm; +import net.lab1024.sa.admin.module.system.department.domain.form.DepartmentUpdateForm; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentTreeVO; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO; +import net.lab1024.sa.admin.module.system.department.service.DepartmentService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 部门 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat 卓大1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_DEPARTMENT) +public class DepartmentController { + + @Resource + private DepartmentService departmentService; + + @Operation(summary = "查询部门树形列表 @author 卓大") + @GetMapping("/department/treeList") + public ResponseDTO> departmentTree() { + return departmentService.departmentTree(); + } + + @Operation(summary = "添加部门 @author 卓大") + @PostMapping("/department/add") + @SaCheckPermission("system:department:add") + public ResponseDTO addDepartment(@Valid @RequestBody DepartmentAddForm createDTO) { + return departmentService.addDepartment(createDTO); + } + + @Operation(summary = "更新部门 @author 卓大") + @PostMapping("/department/update") + @SaCheckPermission("system:department:update") + public ResponseDTO updateDepartment(@Valid @RequestBody DepartmentUpdateForm updateDTO) { + return departmentService.updateDepartment(updateDTO); + } + + @Operation(summary = "删除部门 @author 卓大") + @GetMapping("/department/delete/{departmentId}") + @SaCheckPermission("system:department:delete") + public ResponseDTO deleteDepartment(@PathVariable Long departmentId) { + return departmentService.deleteDepartment(departmentId); + } + + @Operation(summary = "查询部门列表 @author 卓大") + @GetMapping("/department/listAll") + public ResponseDTO> listAll() { + return ResponseDTO.ok(departmentService.listAll()); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/dao/DepartmentDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/dao/DepartmentDao.java new file mode 100644 index 0000000..011f016 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/dao/DepartmentDao.java @@ -0,0 +1,35 @@ +package net.lab1024.sa.admin.module.system.department.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.lab1024.sa.admin.module.system.department.domain.entity.DepartmentEntity; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 部门 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface DepartmentDao extends BaseMapper { + + /** + * 根据部门id,查询此部门直接子部门的数量 + * + */ + Integer countSubDepartment(@Param("departmentId") Long departmentId); + + /** + * 获取全部部门列表 + */ + List listAll(); + + DepartmentVO selectDepartmentVO(@Param("departmentId")Long departmentId); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java new file mode 100644 index 0000000..42d42e9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/entity/DepartmentEntity.java @@ -0,0 +1,65 @@ +package net.lab1024.sa.admin.module.system.department.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.FieldStrategy; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 部门实体类 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName(value = "t_smart_department") +public class DepartmentEntity { + + /** + * 主键id + */ + @TableId(type = IdType.AUTO) + private Long departmentId; + + /** + * 部门名称 + */ + private String departmentName; + + /** + * 负责人员工 id + */ + @TableField(updateStrategy = FieldStrategy.IGNORED) + private Long managerId; + + /** + * 部门父级id + */ + private Long parentId; + + /** + * 排序 + */ + private Integer sort; + + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/form/DepartmentAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/form/DepartmentAddForm.java new file mode 100644 index 0000000..1cba929 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/form/DepartmentAddForm.java @@ -0,0 +1,35 @@ +package net.lab1024.sa.admin.module.system.department.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +/** + * 部门 添加表单 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class DepartmentAddForm { + + @Schema(description = "部门名称") + @Length(min = 1, max = 50, message = "请输入正确的部门名称(1-50个字符)") + @NotNull(message = "请输入正确的部门名称(1-50个字符)") + private String departmentName; + + @Schema(description = "排序") + @NotNull(message = "排序值") + private Integer sort; + + @Schema(description = "部门负责人id") + private Long managerId; + + @Schema(description = "上级部门id (可选)") + private Long parentId; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/form/DepartmentUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/form/DepartmentUpdateForm.java new file mode 100644 index 0000000..a65d232 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/form/DepartmentUpdateForm.java @@ -0,0 +1,23 @@ +package net.lab1024.sa.admin.module.system.department.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 部门 更新表单 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class DepartmentUpdateForm extends DepartmentAddForm { + + @Schema(description = "部门id") + @NotNull(message = "部门id不能为空") + private Long departmentId; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentEmployeeTreeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentEmployeeTreeVO.java new file mode 100644 index 0000000..94bfb71 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentEmployeeTreeVO.java @@ -0,0 +1,27 @@ +package net.lab1024.sa.admin.module.system.department.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO; + +import java.util.List; + +/** + * 部门 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class DepartmentEmployeeTreeVO extends DepartmentVO { + + @Schema(description = "部门员工列表") + private List employees; + + @Schema(description = "子部门") + private List children; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentTreeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentTreeVO.java new file mode 100644 index 0000000..7728f22 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentTreeVO.java @@ -0,0 +1,32 @@ +package net.lab1024.sa.admin.module.system.department.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 部门 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class DepartmentTreeVO extends DepartmentVO { + + @Schema(description = "同级上一个元素id") + private Long preId; + + @Schema(description = "同级下一个元素id") + private Long nextId; + + @Schema(description = "子部门") + private List children; + + @Schema(description = "自己和所有递归子部门的id集合") + private List selfAndAllChildrenIdList; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentVO.java new file mode 100644 index 0000000..43b2a35 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentVO.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.system.department.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 部门 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class DepartmentVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "部门id") + private Long departmentId; + + @Schema(description = "部门名称") + private String departmentName; + + @Schema(description = "部门负责人姓名") + private String managerName; + + @Schema(description = "部门负责人id") + private Long managerId; + + @Schema(description = "父级部门id") + private Long parentId; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/manager/DepartmentCacheManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/manager/DepartmentCacheManager.java new file mode 100644 index 0000000..810d2ff --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/manager/DepartmentCacheManager.java @@ -0,0 +1,226 @@ +package net.lab1024.sa.admin.module.system.department.manager; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.constant.AdminCacheConst; +import net.lab1024.sa.admin.module.system.department.dao.DepartmentDao; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentTreeVO; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 部门 缓存相关 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Slf4j +@Service +public class DepartmentCacheManager { + + @Resource + private DepartmentDao departmentDao; + + private void logClearInfo(String cache) { + log.info("clear " + cache); + } + + @CacheEvict(value = {AdminCacheConst.Department.DEPARTMENT_LIST_CACHE, AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE, AdminCacheConst.Department.DEPARTMENT_TREE_CACHE, AdminCacheConst.Department.DEPARTMENT_PATH_CACHE,}, allEntries = true) + public void clearCache() { + logClearInfo(AdminCacheConst.Department.DEPARTMENT_LIST_CACHE); + } + + + /** + * 部门列表 + */ + @Cacheable(AdminCacheConst.Department.DEPARTMENT_LIST_CACHE) + public List getDepartmentList() { + return departmentDao.listAll(); + } + + /** + * 缓存部门树结构 + */ + @Cacheable(AdminCacheConst.Department.DEPARTMENT_TREE_CACHE) + public List getDepartmentTree() { + List departmentVOList = departmentDao.listAll(); + return this.buildTree(departmentVOList); + } + + /** + * 缓存某个部门的下级id列表 + */ + @Cacheable(AdminCacheConst.Department.DEPARTMENT_SELF_CHILDREN_CACHE) + public List getDepartmentSelfAndChildren(Long departmentId) { + List departmentVOList = departmentDao.listAll(); + return this.selfAndChildrenIdList(departmentId, departmentVOList); + } + + + /** + * 部门的路径名称 + */ + @Cacheable(AdminCacheConst.Department.DEPARTMENT_PATH_CACHE) + public Map getDepartmentPathMap() { + List departmentVOList = departmentDao.listAll(); + Map departmentMap = departmentVOList.stream().collect(Collectors.toMap(DepartmentVO::getDepartmentId, Function.identity())); + + Map pathNameMap = Maps.newHashMap(); + for (DepartmentVO departmentVO : departmentVOList) { + String pathName = this.buildDepartmentPath(departmentVO, departmentMap); + pathNameMap.put(departmentVO.getDepartmentId(), pathName); + } + + return pathNameMap; + } + + /** + * 构建父级考点路径 + */ + private String buildDepartmentPath(DepartmentVO departmentVO, Map departmentMap) { + if (Objects.equals(departmentVO.getParentId(), NumberUtils.LONG_ZERO)) { + return departmentVO.getDepartmentName(); + } + //父节点 + DepartmentVO parentDepartment = departmentMap.get(departmentVO.getParentId()); + if (parentDepartment == null) { + return departmentVO.getDepartmentName(); + } + String pathName = buildDepartmentPath(parentDepartment, departmentMap); + return pathName + "/" + departmentVO.getDepartmentName(); + + } + // ---------------------- 构造树的一些方法 ------------------------------ + + /** + * 构建部门树结构 + */ + public List buildTree(List voList) { + if (CollectionUtils.isEmpty(voList)) { + return Lists.newArrayList(); + } + List rootList = voList.stream().filter(e -> e.getParentId() == null || Objects.equals(e.getParentId(), NumberUtils.LONG_ZERO)).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(rootList)) { + return Lists.newArrayList(); + } + List treeVOList = SmartBeanUtil.copyList(rootList, DepartmentTreeVO.class); + this.recursiveBuildTree(treeVOList, voList); + return treeVOList; + } + + /** + * 构建所有根节点的下级树形结构 + * 返回值为层序遍历结果 + * [由于departmentDao中listAll给出数据根据Sort降序 所以同一层中Sort值较大的优先遍历] + */ + private List recursiveBuildTree(List nodeList, List allDepartmentList) { + int nodeSize = nodeList.size(); + List childIdList = new ArrayList<>(); + for (int i = 0; i < nodeSize; i++) { + int preIndex = i - 1; + int nextIndex = i + 1; + DepartmentTreeVO node = nodeList.get(i); + if (preIndex > -1) { + node.setPreId(nodeList.get(preIndex).getDepartmentId()); + } + if (nextIndex < nodeSize) { + node.setNextId(nodeList.get(nextIndex).getDepartmentId()); + } + + List children = getChildren(node.getDepartmentId(), allDepartmentList); + + List tempChildIdList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(children)) { + node.setChildren(children); + tempChildIdList = this.recursiveBuildTree(children, allDepartmentList); + } + + if (CollectionUtils.isEmpty(node.getSelfAndAllChildrenIdList())) { + node.setSelfAndAllChildrenIdList( + new ArrayList<>() + ); + } + node.getSelfAndAllChildrenIdList().add(node.getDepartmentId()); + + if (CollectionUtils.isNotEmpty(tempChildIdList)) { + node.getSelfAndAllChildrenIdList().addAll(tempChildIdList); + childIdList.addAll(tempChildIdList); + } + + } + + // 保证本层遍历顺序 + for (int i = nodeSize - 1; i >= 0; i--) { + childIdList.add(0, nodeList.get(i).getDepartmentId()); + } + + return childIdList; + } + + + /** + * 获取子元素 + */ + private List getChildren(Long departmentId, List voList) { + List childrenEntityList = voList.stream().filter(e -> departmentId.equals(e.getParentId())).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(childrenEntityList)) { + return Lists.newArrayList(); + } + return SmartBeanUtil.copyList(childrenEntityList, DepartmentTreeVO.class); + } + + + /** + * 通过部门id,获取当前以及下属部门 + */ + public List selfAndChildrenIdList(Long departmentId, List voList) { + List selfAndChildrenIdList = Lists.newArrayList(); + if (CollectionUtils.isEmpty(voList)) { + return selfAndChildrenIdList; + } + selfAndChildrenIdList.add(departmentId); + List children = this.getChildren(departmentId, voList); + if (CollectionUtils.isEmpty(children)) { + return selfAndChildrenIdList; + } + List childrenIdList = children.stream().map(DepartmentTreeVO::getDepartmentId).collect(Collectors.toList()); + selfAndChildrenIdList.addAll(childrenIdList); + for (Long childId : childrenIdList) { + this.selfAndChildrenRecursion(selfAndChildrenIdList, childId, voList); + } + return selfAndChildrenIdList; + } + + /** + * 递归查询 + */ + public void selfAndChildrenRecursion(List selfAndChildrenIdList, Long departmentId, List voList) { + List children = this.getChildren(departmentId, voList); + if (CollectionUtils.isEmpty(children)) { + return; + } + List childrenIdList = children.stream().map(DepartmentTreeVO::getDepartmentId).collect(Collectors.toList()); + selfAndChildrenIdList.addAll(childrenIdList); + for (Long childId : childrenIdList) { + this.selfAndChildrenRecursion(selfAndChildrenIdList, childId, voList); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/service/DepartmentService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/service/DepartmentService.java new file mode 100644 index 0000000..9ef2fbf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/service/DepartmentService.java @@ -0,0 +1,147 @@ +package net.lab1024.sa.admin.module.system.department.service; + +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.department.dao.DepartmentDao; +import net.lab1024.sa.admin.module.system.department.domain.entity.DepartmentEntity; +import net.lab1024.sa.admin.module.system.department.domain.form.DepartmentAddForm; +import net.lab1024.sa.admin.module.system.department.domain.form.DepartmentUpdateForm; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentTreeVO; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO; +import net.lab1024.sa.admin.module.system.department.manager.DepartmentCacheManager; +import net.lab1024.sa.admin.module.system.employee.dao.EmployeeDao; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 部门 service + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-12 20:37:48 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class DepartmentService { + + @Resource + private DepartmentDao departmentDao; + + @Resource + private EmployeeDao employeeDao; + + @Resource + private DepartmentCacheManager departmentCacheManager; + + // ---------------------------- 增加、修改、删除 ---------------------------- + + /** + * 新增添加部门 + */ + + public ResponseDTO addDepartment(DepartmentAddForm departmentAddForm) { + DepartmentEntity departmentEntity = SmartBeanUtil.copy(departmentAddForm, DepartmentEntity.class); + departmentDao.insert(departmentEntity); + this.clearCache(); + return ResponseDTO.ok(); + } + + + /** + * 更新部门信息 + */ + public ResponseDTO updateDepartment(DepartmentUpdateForm updateDTO) { + if (updateDTO.getParentId() == null) { + return ResponseDTO.userErrorParam("父级部门id不能为空"); + } + DepartmentEntity entity = departmentDao.selectById(updateDTO.getDepartmentId()); + if (entity == null) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + DepartmentEntity departmentEntity = SmartBeanUtil.copy(updateDTO, DepartmentEntity.class); + departmentEntity.setSort(updateDTO.getSort()); + departmentDao.updateById(departmentEntity); + this.clearCache(); + return ResponseDTO.ok(); + } + + /** + * 根据id删除部门 + * 1、需要判断当前部门是否有子部门,有子部门则不允许删除 + * 2、需要判断当前部门是否有员工,有员工则不能删除 + */ + public ResponseDTO deleteDepartment(Long departmentId) { + DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); + if (null == departmentEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + // 是否有子级部门 + int subDepartmentNum = departmentDao.countSubDepartment(departmentId); + if (subDepartmentNum > 0) { + return ResponseDTO.userErrorParam("请先删除子级部门"); + } + + // 是否有未删除员工 + int employeeNum = employeeDao.countByDepartmentId(departmentId, Boolean.FALSE); + if (employeeNum > 0) { + return ResponseDTO.userErrorParam("请先删除部门员工"); + } + departmentDao.deleteById(departmentId); + // 清除缓存 + this.clearCache(); + return ResponseDTO.ok(); + } + + /** + * 清除自身以及下级的id列表缓存 + */ + private void clearCache() { + departmentCacheManager.clearCache(); + } + + // ---------------------------- 查询 ---------------------------- + + /** + * 获取部门树形结构 + */ + public ResponseDTO> departmentTree() { + List treeVOList = departmentCacheManager.getDepartmentTree(); + return ResponseDTO.ok(treeVOList); + } + + + /** + * 自身以及所有下级的部门id列表 + */ + public List selfAndChildrenIdList(Long departmentId) { + return departmentCacheManager.getDepartmentSelfAndChildren(departmentId); + } + + + /** + * 获取所有部门 + */ + public List listAll() { + return departmentCacheManager.getDepartmentList(); + } + + + /** + * 获取部门 + */ + public DepartmentVO getDepartmentById(Long departmentId) { + return departmentDao.selectDepartmentVO(departmentId); + } + + /** + * 获取部门路径:/公司/研发部/产品组 + */ + public String getDepartmentPath(Long departmentId) { + return departmentCacheManager.getDepartmentPathMap().get(departmentId); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/controller/EmployeeController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/controller/EmployeeController.java new file mode 100644 index 0000000..2d11e03 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/controller/EmployeeController.java @@ -0,0 +1,129 @@ +package net.lab1024.sa.admin.module.system.employee.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.employee.domain.form.*; +import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO; +import net.lab1024.sa.admin.module.system.employee.service.EmployeeService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.module.support.apiencrypt.annotation.ApiDecrypt; +import net.lab1024.sa.base.module.support.securityprotect.service.Level3ProtectConfigService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 员工 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2021-12-09 22:57:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_EMPLOYEE) +public class EmployeeController { + + @Resource + private EmployeeService employeeService; + + @Resource + private Level3ProtectConfigService level3ProtectConfigService; + + @PostMapping("/employee/query") + @Operation(summary = "员工管理查询 @author 卓大") + public ResponseDTO> query(@Valid @RequestBody EmployeeQueryForm query) { + return employeeService.queryEmployee(query); + } + + @Operation(summary = "添加员工(返回添加员工的密码) @author 卓大") + @PostMapping("/employee/add") + @SaCheckPermission("system:employee:add") + public ResponseDTO addEmployee(@Valid @RequestBody EmployeeAddForm employeeAddForm) { + return employeeService.addEmployee(employeeAddForm); + } + + @Operation(summary = "更新员工 @author 卓大") + @PostMapping("/employee/update") + @SaCheckPermission("system:employee:update") + public ResponseDTO updateEmployee(@Valid @RequestBody EmployeeUpdateForm employeeUpdateForm) { + return employeeService.updateEmployee(employeeUpdateForm); + } + + @Operation(summary = "更新员工个人中心信息 @author 善逸") + @PostMapping("/employee/update/center") + public ResponseDTO updateCenter(@Valid @RequestBody EmployeeUpdateCenterForm updateCenterForm) { + updateCenterForm.setEmployeeId(SmartRequestUtil.getRequestUserId()); + return employeeService.updateCenter(updateCenterForm); + } + + @Operation(summary = "更新登录人头像 @author 善逸") + @PostMapping("/employee/update/avatar") + public ResponseDTO updateAvatar(@Valid @RequestBody EmployeeUpdateAvatarForm employeeUpdateAvatarForm) { + employeeUpdateAvatarForm.setEmployeeId(SmartRequestUtil.getRequestUserId()); + return employeeService.updateAvatar(employeeUpdateAvatarForm); + } + + @Operation(summary = "更新员工禁用/启用状态 @author 卓大") + @GetMapping("/employee/update/disabled/{employeeId}") + @SaCheckPermission("system:employee:disabled") + public ResponseDTO updateDisableFlag(@PathVariable Long employeeId) { + return employeeService.updateDisableFlag(employeeId); + } + + @Operation(summary = "批量删除员工 @author 卓大") + @PostMapping("/employee/update/batch/delete") + @SaCheckPermission("system:employee:delete") + public ResponseDTO batchUpdateDeleteFlag(@RequestBody List employeeIdList) { + return employeeService.batchUpdateDeleteFlag(employeeIdList); + } + + @Operation(summary = "批量调整员工部门 @author 卓大") + @PostMapping("/employee/update/batch/department") + @SaCheckPermission("system:employee:department:update") + public ResponseDTO batchUpdateDepartment(@Valid @RequestBody EmployeeBatchUpdateDepartmentForm batchUpdateDepartmentForm) { + return employeeService.batchUpdateDepartment(batchUpdateDepartmentForm); + } + + @Operation(summary = "修改密码 @author 卓大") + @PostMapping("/employee/update/password") + @ApiDecrypt + public ResponseDTO updatePassword(@Valid @RequestBody EmployeeUpdatePasswordForm updatePasswordForm) { + updatePasswordForm.setEmployeeId(SmartRequestUtil.getRequestUserId()); + return employeeService.updatePassword(SmartRequestUtil.getRequestUser(), updatePasswordForm); + } + + @Operation(summary = "获取密码复杂度 @author 卓大") + @GetMapping("/employee/getPasswordComplexityEnabled") + @ApiDecrypt + public ResponseDTO getPasswordComplexityEnabled() { + return ResponseDTO.ok(level3ProtectConfigService.isPasswordComplexityEnabled()); + } + + @Operation(summary = "重置员工密码 @author 卓大") + @GetMapping("/employee/update/password/reset/{employeeId}") + @SaCheckPermission("system:employee:password:reset") + public ResponseDTO resetPassword(@PathVariable Long employeeId) { + return employeeService.resetPassword(employeeId); + } + + @Operation(summary = "查询员工-根据部门id @author 卓大") + @GetMapping("/employee/getAllEmployeeByDepartmentId/{departmentId}") + public ResponseDTO> getAllEmployeeByDepartmentId(@PathVariable Long departmentId) { + return employeeService.getAllEmployeeByDepartmentId(departmentId); + } + + @Operation(summary = "查询所有员工 @author 卓大") + @GetMapping("/employee/queryAll") + public ResponseDTO> queryAllEmployee(@RequestParam(value = "disabledFlag", required = false) Boolean disabledFlag) { + return employeeService.queryAllEmployee(disabledFlag); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/dao/EmployeeDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/dao/EmployeeDao.java new file mode 100644 index 0000000..1b02fad --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/dao/EmployeeDao.java @@ -0,0 +1,111 @@ +package net.lab1024.sa.admin.module.system.employee.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; +import net.lab1024.sa.admin.module.system.employee.domain.form.EmployeeQueryForm; +import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; + +/** + * 员工 dao + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2021-12-09 22:57:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface EmployeeDao extends BaseMapper { + /** + * 查询员工列表 + */ + List queryEmployee(Page page, @Param("queryForm") EmployeeQueryForm queryForm, @Param("departmentIdList") List departmentIdList); + + /** + * 查询员工 + */ + List selectEmployeeByDisabledAndDeleted(@Param("disabledFlag") Boolean disabledFlag, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 更新单个 + */ + void updateDisableFlag(@Param("employeeId") Long employeeId, @Param("disabledFlag") Boolean disabledFlag); + + /** + * 通过登录名查询 + */ + EmployeeEntity getByLoginName(@Param("loginName") String loginName, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 通过姓名查询 + */ + EmployeeEntity getByActualName(@Param("actualName") String actualName, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 通过手机号查询 + */ + EmployeeEntity getByPhone(@Param("phone") String phone, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 通过邮箱账号查询 + */ + EmployeeEntity getByEmail(@Param("email") String email, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 获取所有员工 + */ + List listAll(); + + /** + * 获取某个部门员工数 + */ + Integer countByDepartmentId(@Param("departmentId") Long departmentId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 获取一批员工 + */ + List getEmployeeByIds(@Param("employeeIds") Collection employeeIds); + + /** + * 查询单个员工信息 + */ + EmployeeVO getEmployeeById(@Param("employeeId") Long employeeId); + + /** + * 获取某个部门的员工 + */ + List selectByDepartmentId(@Param("departmentId") Long departmentId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 查询某些部门下用户名是xxx的员工 + */ + List selectByActualName(@Param("departmentIdList") List departmentIdList, @Param("actualName") String actualName, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 获取某批部门的员工Id + */ + List getEmployeeIdByDepartmentIdList(@Param("departmentIds") List departmentIds, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 获取所有 + */ + List getEmployeeId(@Param("leaveFlag") Boolean leaveFlag, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 获取某个部门的员工Id + */ + List getEmployeeIdByDepartmentId(@Param("departmentId") Long departmentId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 员工重置密码 + */ + Integer updatePassword(@Param("employeeId") Long employeeId, @Param("password") String password); + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java new file mode 100644 index 0000000..43e01ae --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java @@ -0,0 +1,96 @@ +package net.lab1024.sa.admin.module.system.employee.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 员工 实体表 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2021-12-09 22:57:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_employee") +public class EmployeeEntity { + + @TableId(type = IdType.AUTO) + private Long employeeId; + + /** + * 登录账号 + */ + private String loginName; + + /** + * 登录密码 + */ + private String loginPwd; + + /** + * 员工名称 + */ + private String actualName; + + /** + * 头像 + */ + private String avatar; + + /** + * 性别 + */ + private Integer gender; + + /** + * 手机号码 + */ + private String phone; + + /** + * 邮箱 + */ + private String email; + + /** + * 部门id + */ + private Long departmentId; + + /** + * 职务级别ID + */ + private Long positionId; + + /** + * 是否为超级管理员: 0 不是,1是 + */ + private Boolean administratorFlag; + + /** + * 是否被禁用 0否1是 + */ + private Boolean disabledFlag; + + /** + * 是否删除0否 1是 + */ + private Boolean deletedFlag; + + /** + * 备注 + */ + private String remark; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeAddForm.java new file mode 100644 index 0000000..00792d2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeAddForm.java @@ -0,0 +1,69 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import net.lab1024.sa.base.common.enumeration.GenderEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.util.SmartVerificationUtil; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import org.hibernate.validator.constraints.Length; + +import java.util.List; + +/** + * 添加员工 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-20 21:06:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeAddForm { + + @Schema(description = "姓名") + @NotNull(message = "姓名不能为空") + @Length(max = 30, message = "姓名最多30字符") + private String actualName; + + @Schema(description = "登录账号") + @NotNull(message = "登录账号不能为空") + @Length(max = 30, message = "登录账号最多30字符") + private String loginName; + + @SchemaEnum(GenderEnum.class) + @CheckEnum(value = GenderEnum.class, message = "性别错误") + private Integer gender; + + @Schema(description = "部门id") + @NotNull(message = "部门id不能为空") + private Long departmentId; + + @Schema(description = "是否启用") + @NotNull(message = "是否被禁用不能为空") + private Boolean disabledFlag; + + @Schema(description = "手机号") + @NotNull(message = "手机号不能为空") + @Pattern(regexp = SmartVerificationUtil.PHONE_REGEXP, message = "手机号格式不正确") + private String phone; + + @Schema(description = "邮箱账号") + @NotNull(message = "邮箱账号不能为空") + @Pattern(regexp = SmartVerificationUtil.EMAIL, message = "邮箱账号格式不正确") + private String email; + + @Schema(description = "职务级别ID") + private Long positionId; + + @Schema(description = "角色列表") + private List roleIdList; + + @Schema(description = "备注") + @Length(max = 200, message = "备注最多200字符") + private String remark; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeBatchUpdateDepartmentForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeBatchUpdateDepartmentForm.java new file mode 100644 index 0000000..737f2c3 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeBatchUpdateDepartmentForm.java @@ -0,0 +1,31 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.List; + +/** + * 员工更新部门 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-20 21:06:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeBatchUpdateDepartmentForm { + + @Schema(description = "员工id") + @NotEmpty(message = "员工id不能为空") + @Size(max = 99, message = "一次最多调整99个员工") + private List employeeIdList; + + @Schema(description = "部门ID") + @NotNull(message = "部门ID不能为空") + private Long departmentId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeQueryForm.java new file mode 100644 index 0000000..ef467a2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeQueryForm.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Size; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; +import org.hibernate.validator.constraints.Length; + +import java.util.List; + +/** + * 员工列表 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-20 21:06:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeQueryForm extends PageParam { + + @Schema(description = "搜索词") + @Length(max = 20, message = "搜索词最多20字符") + private String keyword; + + @Schema(description = "部门id") + private Long departmentId; + + @Schema(description = "是否禁用") + private Boolean disabledFlag; + + @Schema(description = "员工id集合") + @Size(max = 99, message = "最多查询99个员工") + private List employeeIdList; + + @Schema(description = "删除标识", hidden = true) + private Boolean deletedFlag; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateAvatarForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateAvatarForm.java new file mode 100644 index 0000000..03feb56 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateAvatarForm.java @@ -0,0 +1,25 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +/** + * 修改登录人头像 + * + * @Author 1024创新实验室: 善逸 + * @Date 2024年6月30日00:26:35 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeUpdateAvatarForm { + + @Schema(hidden = true) + private Long employeeId; + + @Schema(description = "头像") + @NotBlank(message = "头像不能为空哦") + private String avatar; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateCenterForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateCenterForm.java new file mode 100644 index 0000000..d28252c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateCenterForm.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import net.lab1024.sa.base.common.enumeration.GenderEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.util.SmartVerificationUtil; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import org.hibernate.validator.constraints.Length; + +/** + * 更新员工个人中心信息 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-20 21:06:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeUpdateCenterForm { + + @Schema(hidden = true) + private Long employeeId; + + @Schema(description = "姓名") + @NotNull(message = "姓名不能为空") + @Length(max = 30, message = "姓名最多30字符") + private String actualName; + + @SchemaEnum(GenderEnum.class) + @CheckEnum(value = GenderEnum.class, message = "性别错误") + private Integer gender; + + @Schema(description = "手机号") + @NotNull(message = "手机号不能为空") + @Pattern(regexp = SmartVerificationUtil.PHONE_REGEXP, message = "手机号格式不正确") + private String phone; + + @Schema(description = "邮箱账号") + @NotNull(message = "邮箱账号不能为空") + @Pattern(regexp = SmartVerificationUtil.EMAIL, message = "邮箱账号格式不正确") + private String email; + + @Schema(description = "职务级别ID") + private Long positionId; + + @Schema(description = "头像") + private String avatar; + + @Schema(description = "备注") + @Length(max = 200, message = "备注最多200字符") + private String remark; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateForm.java new file mode 100644 index 0000000..8a72c79 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateForm.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 更新员工 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-20 21:06:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeUpdateForm extends EmployeeAddForm { + + @Schema(description = "员工id") + @NotNull(message = "员工id不能为空") + private Long employeeId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdatePasswordForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdatePasswordForm.java new file mode 100644 index 0000000..07202e2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdatePasswordForm.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +/** + * 修改密码所需参数 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-20 21:06:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeUpdatePasswordForm { + + @Schema(hidden = true) + private Long employeeId; + + @Schema(description = "原密码") + @NotBlank(message = "原密码不能为空哦") + private String oldPassword; + + @Schema(description = "新密码") + @NotBlank(message = "新密码不能为空哦") + private String newPassword; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateRoleForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateRoleForm.java new file mode 100644 index 0000000..1f3dc2c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateRoleForm.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +import java.util.List; + +/** + * 员工更新角色 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2021-12-20 20:55:13 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeUpdateRoleForm { + + @Schema(description = "员工id") + @NotNull(message = "员工id不能为空") + private Long employeeId; + + @Schema(description = "角色ids") + @Size(max = 99, message = "角色最多99") + private List roleIdList; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/vo/EmployeeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/vo/EmployeeVO.java new file mode 100644 index 0000000..a4b620a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/vo/EmployeeVO.java @@ -0,0 +1,68 @@ +package net.lab1024.sa.admin.module.system.employee.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.enumeration.GenderEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 员工信息 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2021-12-21 23:05:56 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeVO { + + @Schema(description = "主键id") + private Long employeeId; + + @Schema(description = "登录账号") + private String loginName; + + @SchemaEnum(GenderEnum.class) + private Integer gender; + + @Schema(description = "员工名称") + private String actualName; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "部门id") + private Long departmentId; + + @Schema(description = "是否被禁用") + private Boolean disabledFlag; + + @Schema(description = "是否 超级管理员") + private Boolean administratorFlag; + + @Schema(description = "部门名称") + private String departmentName; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "角色列表") + private List roleIdList; + + @Schema(description = "角色名称列表") + private List roleNameList; + + @Schema(description = "职务ID") + private Long positionId; + + @Schema(description = "职务名称") + private String positionName; + + @Schema(description = "邮箱") + private String email; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/manager/EmployeeManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/manager/EmployeeManager.java new file mode 100644 index 0000000..23d05d1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/manager/EmployeeManager.java @@ -0,0 +1,86 @@ +package net.lab1024.sa.admin.module.system.employee.manager; + + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.employee.dao.EmployeeDao; +import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; +import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEmployeeEntity; +import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 员工 manager + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-12-29 21:52:46 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class EmployeeManager extends ServiceImpl { + + @Resource + private EmployeeDao employeeDao; + + @Resource + private RoleEmployeeService roleEmployeeService; + + @Resource + private RoleEmployeeDao roleEmployeeDao; + + /** + * 保存员工 + * + */ + @Transactional(rollbackFor = Throwable.class) + public void saveEmployee(EmployeeEntity employee, List roleIdList) { + // 保存员工 获得id + employeeDao.insert(employee); + + if (CollectionUtils.isNotEmpty(roleIdList)) { + List roleEmployeeList = roleIdList.stream().map(e -> new RoleEmployeeEntity(e, employee.getEmployeeId())).collect(Collectors.toList()); + roleEmployeeService.batchInsert(roleEmployeeList); + } + } + + /** + * 更新员工 + * + */ + @Transactional(rollbackFor = Throwable.class) + public void updateEmployee(EmployeeEntity employee, List roleIdList) { + // 保存员工 获得id + employeeDao.updateById(employee); + + // 若为空,则删除所有角色 + if (CollectionUtils.isEmpty(roleIdList)) { + roleEmployeeDao.deleteByEmployeeId(employee.getEmployeeId()); + return; + } + + List roleEmployeeList = roleIdList.stream().map(e -> new RoleEmployeeEntity(e, employee.getEmployeeId())).collect(Collectors.toList()); + this.updateEmployeeRole(employee.getEmployeeId(), roleEmployeeList); + } + + /** + * 更新员工角色 + */ + @Transactional(rollbackFor = Throwable.class) + public void updateEmployeeRole(Long employeeId, List roleEmployeeList) { + + roleEmployeeDao.deleteByEmployeeId(employeeId); + + if (CollectionUtils.isNotEmpty(roleEmployeeList)) { + roleEmployeeService.batchInsert(roleEmployeeList); + } + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java new file mode 100644 index 0000000..65352b5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java @@ -0,0 +1,429 @@ +package net.lab1024.sa.admin.module.system.employee.service; + +import cn.dev33.satoken.stp.StpUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.department.dao.DepartmentDao; +import net.lab1024.sa.admin.module.system.department.domain.entity.DepartmentEntity; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO; +import net.lab1024.sa.admin.module.system.department.service.DepartmentService; +import net.lab1024.sa.admin.module.system.employee.dao.EmployeeDao; +import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; +import net.lab1024.sa.admin.module.system.employee.domain.form.*; +import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO; +import net.lab1024.sa.admin.module.system.employee.manager.EmployeeManager; +import net.lab1024.sa.admin.module.system.login.service.LoginService; +import net.lab1024.sa.admin.module.system.position.dao.PositionDao; +import net.lab1024.sa.admin.module.system.position.domain.entity.PositionEntity; +import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleEmployeeVO; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.constant.StringConst; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.enumeration.UserTypeEnum; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.securityprotect.service.SecurityPasswordService; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 员工 service + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2021-12-29 21:52:46 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class EmployeeService { + + @Resource + private EmployeeDao employeeDao; + + @Resource + private DepartmentDao departmentDao; + + @Resource + private EmployeeManager employeeManager; + + @Resource + private RoleEmployeeDao roleEmployeeDao; + + @Resource + private DepartmentService departmentService; + + @Resource + private SecurityPasswordService securityPasswordService; + + @Resource + @Lazy + private LoginService loginService; + + @Resource + private PositionDao positionDao; + + public EmployeeEntity getById(Long employeeId) { + return employeeDao.selectById(employeeId); + } + + + /** + * 查询员工列表 + */ + public ResponseDTO> queryEmployee(EmployeeQueryForm employeeQueryForm) { + employeeQueryForm.setDeletedFlag(false); + Page pageParam = SmartPageUtil.convert2PageQuery(employeeQueryForm); + + List departmentIdList = new ArrayList<>(); + if (employeeQueryForm.getDepartmentId() != null) { + departmentIdList.addAll(departmentService.selfAndChildrenIdList(employeeQueryForm.getDepartmentId())); + } + + List employeeList = employeeDao.queryEmployee(pageParam, employeeQueryForm, departmentIdList); + if (CollectionUtils.isEmpty(employeeList)) { + PageResult pageResult = SmartPageUtil.convert2PageResult(pageParam, employeeList); + return ResponseDTO.ok(pageResult); + } + + // 查询员工角色 + List employeeIdList = employeeList.stream().map(EmployeeVO::getEmployeeId).collect(Collectors.toList()); + List roleEmployeeEntityList = employeeIdList.isEmpty() ? Collections.emptyList() : roleEmployeeDao.selectRoleByEmployeeIdList(employeeIdList); + Map> employeeRoleIdListMap = roleEmployeeEntityList.stream().collect(Collectors.groupingBy(RoleEmployeeVO::getEmployeeId, Collectors.mapping(RoleEmployeeVO::getRoleId, Collectors.toList()))); + Map> employeeRoleNameListMap = roleEmployeeEntityList.stream().collect(Collectors.groupingBy(RoleEmployeeVO::getEmployeeId, Collectors.mapping(RoleEmployeeVO::getRoleName, Collectors.toList()))); + + // 查询员工职位 + List positionIdList = employeeList.stream().map(EmployeeVO::getPositionId).filter(Objects::nonNull).collect(Collectors.toList()); + List positionEntityList = positionIdList.isEmpty() ? Collections.emptyList() : positionDao.selectBatchIds(positionIdList); + Map positionNameMap = positionEntityList.stream().collect(Collectors.toMap(PositionEntity::getPositionId, PositionEntity::getPositionName)); + + employeeList.forEach(e -> { + e.setRoleIdList(employeeRoleIdListMap.getOrDefault(e.getEmployeeId(), Lists.newArrayList())); + e.setRoleNameList(employeeRoleNameListMap.getOrDefault(e.getEmployeeId(), Lists.newArrayList())); + e.setDepartmentName(departmentService.getDepartmentPath(e.getDepartmentId())); + e.setPositionName(positionNameMap.get(e.getPositionId())); + }); + PageResult pageResult = SmartPageUtil.convert2PageResult(pageParam, employeeList); + return ResponseDTO.ok(pageResult); + } + + /** + * 新增员工 + */ + public synchronized ResponseDTO addEmployee(EmployeeAddForm employeeAddForm) { + // 校验登录名是否重复 + EmployeeEntity employeeEntity = employeeDao.getByLoginName(employeeAddForm.getLoginName(), null); + if (null != employeeEntity) { + return ResponseDTO.userErrorParam("登录名重复"); + } + // 校验电话是否存在 + employeeEntity = employeeDao.getByPhone(employeeAddForm.getPhone(), null); + if (null != employeeEntity) { + return ResponseDTO.userErrorParam("手机号已存在"); + } + // 部门是否存在 + Long departmentId = employeeAddForm.getDepartmentId(); + DepartmentEntity department = departmentDao.selectById(departmentId); + if (department == null) { + return ResponseDTO.userErrorParam("部门不存在"); + } + + EmployeeEntity entity = SmartBeanUtil.copy(employeeAddForm, EmployeeEntity.class); + + // 设置密码 默认密码 + String password = securityPasswordService.randomPassword(); + entity.setLoginPwd(SecurityPasswordService.getEncryptPwd(password)); + + // 保存数据 + entity.setDeletedFlag(Boolean.FALSE); + employeeManager.saveEmployee(entity, employeeAddForm.getRoleIdList()); + + return ResponseDTO.ok(password); + } + + /** + * 更新员工 + */ + public synchronized ResponseDTO updateEmployee(EmployeeUpdateForm employeeUpdateForm) { + + Long employeeId = employeeUpdateForm.getEmployeeId(); + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (null == employeeEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + + // 部门是否存在 + Long departmentId = employeeUpdateForm.getDepartmentId(); + DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); + if (departmentEntity == null) { + return ResponseDTO.userErrorParam("部门不存在"); + } + + // 检查唯一性 + ResponseDTO checkResponse = checkUniqueness(employeeId, employeeUpdateForm.getLoginName(), employeeUpdateForm.getPhone(), employeeUpdateForm.getEmail()); + if (!checkResponse.getOk()) { + return checkResponse; + } + + EmployeeEntity entity = SmartBeanUtil.copy(employeeUpdateForm, EmployeeEntity.class); + // 不更新密码 + entity.setLoginPwd(null); + + // 更新数据 + employeeManager.updateEmployee(entity, employeeUpdateForm.getRoleIdList()); + + // 清除员工缓存 + loginService.clearLoginEmployeeCache(employeeId); + + return ResponseDTO.ok(); + } + + /** + * 更新员工个人中心信息 + */ + public ResponseDTO updateCenter(EmployeeUpdateCenterForm updateCenterForm) { + + Long employeeId = updateCenterForm.getEmployeeId(); + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (null == employeeEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + + // 检查唯一性 登录账号不能修改则不需要检查 + ResponseDTO checkResponse = checkUniqueness(employeeId, "", updateCenterForm.getPhone(), updateCenterForm.getEmail()); + if (!checkResponse.getOk()) { + return checkResponse; + } + + EmployeeEntity employee = SmartBeanUtil.copy(updateCenterForm, EmployeeEntity.class); + // 不更新密码 + employee.setLoginPwd(null); + + // 更新数据 + employeeDao.updateById(employee); + + // 清除员工缓存 + loginService.clearLoginEmployeeCache(employeeId); + + return ResponseDTO.ok(); + } + + /** + * 检查唯一性 + */ + private ResponseDTO checkUniqueness(Long employeeId, String loginName, String phone, String email) { + EmployeeEntity existEntity = employeeDao.getByLoginName(loginName, null); + if (null != existEntity && !Objects.equals(existEntity.getEmployeeId(), employeeId)) { + return ResponseDTO.userErrorParam("登录名重复"); + } + + existEntity = employeeDao.getByPhone(phone, null); + if (null != existEntity && !Objects.equals(existEntity.getEmployeeId(), employeeId)) { + return ResponseDTO.userErrorParam("手机号已存在"); + } + + existEntity = employeeDao.getByEmail(email, null); + if (null != existEntity && !Objects.equals(existEntity.getEmployeeId(), employeeId)) { + return ResponseDTO.userErrorParam("邮箱账号已存在"); + } + + return ResponseDTO.ok(); + } + + /** + * 更新登录人头像 + * + */ + public ResponseDTO updateAvatar(EmployeeUpdateAvatarForm employeeUpdateAvatarForm) { + Long employeeId = employeeUpdateAvatarForm.getEmployeeId(); + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (employeeEntity == null) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + // 更新头像 + EmployeeEntity updateEntity = new EmployeeEntity(); + updateEntity.setEmployeeId(employeeId); + updateEntity.setAvatar(employeeUpdateAvatarForm.getAvatar()); + employeeDao.updateById(updateEntity); + + // 清除员工缓存 + loginService.clearLoginEmployeeCache(employeeId); + return ResponseDTO.ok(); + } + + /** + * 更新禁用/启用状态 + */ + public ResponseDTO updateDisableFlag(Long employeeId) { + if (null == employeeId) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (null == employeeEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + employeeDao.updateDisableFlag(employeeId, !employeeEntity.getDisabledFlag()); + + if (employeeEntity.getDisabledFlag()) { + // 强制退出登录 + StpUtil.logout(UserTypeEnum.ADMIN_EMPLOYEE.getValue() + StringConst.COLON + employeeId); + } + + return ResponseDTO.ok(); + } + + /** + * 批量删除员工 + */ + public ResponseDTO batchUpdateDeleteFlag(List employeeIdList) { + if (CollectionUtils.isEmpty(employeeIdList)) { + return ResponseDTO.ok(); + } + List employeeEntityList = employeeManager.listByIds(employeeIdList); + if (CollectionUtils.isEmpty(employeeEntityList)) { + return ResponseDTO.ok(); + } + // 更新删除 + List deleteList = employeeIdList.stream().map(e -> { + EmployeeEntity updateEmployee = new EmployeeEntity(); + updateEmployee.setEmployeeId(e); + updateEmployee.setDeletedFlag(true); + return updateEmployee; + }).collect(Collectors.toList()); + employeeManager.updateBatchById(deleteList); + + for (Long employeeId : employeeIdList) { + // 强制退出登录 + StpUtil.logout(UserTypeEnum.ADMIN_EMPLOYEE.getValue() + StringConst.COLON + employeeId); + } + return ResponseDTO.ok(); + } + + + /** + * 批量更新部门 + */ + public ResponseDTO batchUpdateDepartment(EmployeeBatchUpdateDepartmentForm batchUpdateDepartmentForm) { + List employeeIdList = batchUpdateDepartmentForm.getEmployeeIdList(); + List employeeEntityList = employeeDao.selectBatchIds(employeeIdList); + if (employeeIdList.size() != employeeEntityList.size()) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + // 更新 + List updateList = employeeIdList.stream().map(e -> { + EmployeeEntity updateEmployee = new EmployeeEntity(); + updateEmployee.setEmployeeId(e); + updateEmployee.setDepartmentId(batchUpdateDepartmentForm.getDepartmentId()); + return updateEmployee; + }).collect(Collectors.toList()); + employeeManager.updateBatchById(updateList); + + return ResponseDTO.ok(); + } + + + /** + * 更新密码 + */ + @Transactional(rollbackFor = Throwable.class) + public ResponseDTO updatePassword(RequestUser requestUser, EmployeeUpdatePasswordForm updatePasswordForm) { + Long employeeId = updatePasswordForm.getEmployeeId(); + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (employeeEntity == null) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + + // 校验原始密码 + if (!SecurityPasswordService.matchesPwd(updatePasswordForm.getOldPassword(),employeeEntity.getLoginPwd()) ) { + return ResponseDTO.userErrorParam("原密码有误,请重新输入"); + } + + // 新旧密码相同 + if (Objects.equals(updatePasswordForm.getOldPassword(), updatePasswordForm.getNewPassword()) ){ + return ResponseDTO.userErrorParam("新密码与原始密码相同,请重新输入"); + } + + // 校验密码复杂度 + ResponseDTO validatePassComplexity = securityPasswordService.validatePasswordComplexity(updatePasswordForm.getNewPassword()); + if (!validatePassComplexity.getOk()) { + return validatePassComplexity; + } + + // 根据三级等保规则,校验密码是否重复 + ResponseDTO passwordRepeatTimes = securityPasswordService.validatePasswordRepeatTimes(requestUser, updatePasswordForm.getNewPassword()); + if (!passwordRepeatTimes.getOk()) { + return ResponseDTO.error(passwordRepeatTimes); + } + + + // 更新密码 + String newEncryptPassword = SecurityPasswordService.getEncryptPwd(updatePasswordForm.getNewPassword()); + EmployeeEntity updateEntity = new EmployeeEntity(); + updateEntity.setEmployeeId(employeeId); + updateEntity.setLoginPwd(newEncryptPassword); + employeeDao.updateById(updateEntity); + + // 保存修改密码密码记录 + securityPasswordService.saveUserChangePasswordLog(requestUser, newEncryptPassword, employeeEntity.getLoginPwd()); + + return ResponseDTO.ok(); + } + + /** + * 获取某个部门的员工信息 + */ + public ResponseDTO> getAllEmployeeByDepartmentId(Long departmentId) { + List employeeEntityList = employeeDao.selectByDepartmentId(departmentId, Boolean.FALSE); + + if (CollectionUtils.isEmpty(employeeEntityList)) { + return ResponseDTO.ok(Collections.emptyList()); + } + + DepartmentVO department = departmentService.getDepartmentById(departmentId); + + List voList = employeeEntityList.stream().map(e -> { + EmployeeVO employeeVO = SmartBeanUtil.copy(e, EmployeeVO.class); + if (department != null) { + employeeVO.setDepartmentName(department.getDepartmentName()); + } + return employeeVO; + }).collect(Collectors.toList()); + return ResponseDTO.ok(voList); + } + + + /** + * 重置密码 + */ + public ResponseDTO resetPassword(Long employeeId) { + String password = securityPasswordService.randomPassword(); + employeeDao.updatePassword(employeeId, SecurityPasswordService.getEncryptPwd(password)); + return ResponseDTO.ok(password); + } + + + /** + * 查询全部员工 + */ + public ResponseDTO> queryAllEmployee(Boolean disabledFlag) { + List employeeList = employeeDao.selectEmployeeByDisabledAndDeleted(disabledFlag, Boolean.FALSE); + return ResponseDTO.ok(employeeList); + } + + /** + * 根据登录名获取员工 + */ + public EmployeeEntity getByLoginName(String loginName) { + return employeeDao.getByLoginName(loginName, false); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java new file mode 100644 index 0000000..28aa85e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/controller/LoginController.java @@ -0,0 +1,89 @@ +package net.lab1024.sa.admin.module.system.login.controller; + +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.extra.servlet.JakartaServletUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.login.domain.LoginForm; +import net.lab1024.sa.admin.module.system.login.domain.LoginResultVO; +import net.lab1024.sa.admin.module.system.login.service.LoginService; +import net.lab1024.sa.admin.util.AdminRequestUtil; +import net.lab1024.sa.base.common.annoation.NoNeedLogin; +import net.lab1024.sa.base.common.constant.RequestHeaderConst; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.module.support.captcha.domain.CaptchaVO; +import net.lab1024.sa.base.module.support.securityprotect.service.Level3ProtectConfigService; +import org.springframework.web.bind.annotation.*; + +/** + * 员工登录 + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2021-12-15 21:05:46 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_LOGIN) +public class LoginController { + + @Resource + private LoginService loginService; + + @Resource + private Level3ProtectConfigService level3ProtectConfigService; + + @NoNeedLogin + @PostMapping("/login") + @Operation(summary = "登录 @author 卓大") + public ResponseDTO login(@Valid @RequestBody LoginForm loginForm, HttpServletRequest request) { + String ip = JakartaServletUtil.getClientIP(request); + String userAgent = JakartaServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT); + return loginService.login(loginForm, ip, userAgent); + } + + @GetMapping("/login/getLoginInfo") + @Operation(summary = "获取登录结果信息 @author 卓大") + public ResponseDTO getLoginInfo() { + String tokenValue = StpUtil.getTokenValue(); + LoginResultVO loginResult = loginService.getLoginResult(AdminRequestUtil.getRequestUser(), tokenValue); + loginResult.setToken(tokenValue); + return ResponseDTO.ok(loginResult); + } + + @Operation(summary = "退出登陆 @author 卓大") + @GetMapping("/login/logout") + public ResponseDTO logout() { + return loginService.logout(SmartRequestUtil.getRequestUser()); + } + + @Operation(summary = "获取验证码 @author 卓大") + @GetMapping("/login/getCaptcha") + @NoNeedLogin + public ResponseDTO getCaptcha() { + return loginService.getCaptcha(); + } + + @NoNeedLogin + @GetMapping("/login/sendEmailCode/{loginName}") + @Operation(summary = "获取邮箱登录验证码 @author 卓大") + public ResponseDTO sendEmailCode(@PathVariable String loginName) { + return loginService.sendEmailCode(loginName); + } + + + @NoNeedLogin + @GetMapping("/login/getTwoFactorLoginFlag") + @Operation(summary = "获取双因子登录标识 @author 卓大") + public ResponseDTO getTwoFactorLoginFlag() { + // 双因子登录 + boolean twoFactorLoginEnabled = level3ProtectConfigService.isTwoFactorLoginEnabled(); + return ResponseDTO.ok(twoFactorLoginEnabled); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/LoginForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/LoginForm.java new file mode 100644 index 0000000..94fb5b8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/LoginForm.java @@ -0,0 +1,39 @@ +package net.lab1024.sa.admin.module.system.login.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import net.lab1024.sa.base.constant.LoginDeviceEnum; +import net.lab1024.sa.base.module.support.captcha.domain.CaptchaForm; +import org.hibernate.validator.constraints.Length; + +/** + * 员工登录 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-19 11:49:45 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class LoginForm extends CaptchaForm { + + @Schema(description = "登录账号") + @NotBlank(message = "登录账号不能为空") + @Length(max = 30, message = "登录账号最多30字符") + private String loginName; + + @Schema(description = "密码") + @NotBlank(message = "密码不能为空") + private String password; + + @SchemaEnum(desc = "登录终端", value = LoginDeviceEnum.class) + @CheckEnum(value = LoginDeviceEnum.class, required = true, message = "此终端不允许登录") + private Integer loginDevice; + + @Schema(description = "邮箱验证码") + private String emailCode; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/LoginResultVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/LoginResultVO.java new file mode 100644 index 0000000..7ab52c6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/LoginResultVO.java @@ -0,0 +1,44 @@ +package net.lab1024.sa.admin.module.system.login.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO; +import net.minidev.json.annotate.JsonIgnore; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 登录结果信息 + * + * @Author 1024创新实验室: 开云 + * @Date 2021-12-19 11:49:45 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class LoginResultVO extends RequestEmployee { + + @Schema(description = "token") + private String token; + + @Schema(description = "菜单列表") + private List menuList; + + @Schema(description = "是否需要修改密码") + private Boolean needUpdatePwdFlag; + + @Schema(description = "上次登录ip") + private String lastLoginIp; + + @Schema(description = "上次登录ip地区") + private String lastLoginIpRegion; + + @Schema(description = "上次登录user-agent") + private String lastLoginUserAgent; + + @Schema(description = "上次登录时间") + private LocalDateTime lastLoginTime; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java new file mode 100644 index 0000000..783ae44 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java @@ -0,0 +1,81 @@ +package net.lab1024.sa.admin.module.system.login.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.enumeration.GenderEnum; +import net.lab1024.sa.base.common.enumeration.UserTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; + +import java.io.Serializable; + +/** + * 请求员工登录信息 + * + * @Author 1024创新实验室: 善逸 + * @Date 2021/8/4 21:15 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RequestEmployee implements RequestUser, Serializable { + + @Schema(description = "员工id") + private Long employeeId; + + @SchemaEnum(UserTypeEnum.class) + private UserTypeEnum userType; + + @Schema(description = "登录账号") + private String loginName; + + @Schema(description = "员工名称") + private String actualName; + + @Schema(description = "头像") + private String avatar; + + @SchemaEnum(GenderEnum.class) + private Integer gender; + + @Schema(description = "手机号码") + private String phone; + + @Schema(description = "部门id") + private Long departmentId; + + @Schema(description = "部门名称") + private String departmentName; + + @Schema(description = "职务级别ID") + private Long positionId; + + @Schema(description = "邮箱") + private String email; + + @Schema(description = "是否禁用") + private Boolean disabledFlag; + + @Schema(description = "是否为超管") + private Boolean administratorFlag; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "请求ip") + private String ip; + + @Schema(description = "请求user-agent") + private String userAgent; + + @Override + public Long getUserId() { + return employeeId; + } + + @Override + public String getUserName() { + return actualName; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/manager/LoginManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/manager/LoginManager.java new file mode 100644 index 0000000..434e4ec --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/manager/LoginManager.java @@ -0,0 +1,162 @@ +package net.lab1024.sa.admin.module.system.login.manager; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.constant.AdminCacheConst; +import net.lab1024.sa.admin.module.system.department.domain.vo.DepartmentVO; +import net.lab1024.sa.admin.module.system.department.service.DepartmentService; +import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; +import net.lab1024.sa.admin.module.system.employee.service.EmployeeService; +import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO; +import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService; +import net.lab1024.sa.admin.module.system.role.service.RoleMenuService; +import net.lab1024.sa.base.common.constant.StringConst; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.UserPermission; +import net.lab1024.sa.base.common.enumeration.UserTypeEnum; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.module.support.file.service.IFileStorageService; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 登录Manager + * + * @Author 1024创新实验室: 卓大 + * @Date 2025-05-03 22:56:34 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Slf4j +@Service +public class LoginManager { + + @Resource + private DepartmentService departmentService; + + @Resource + private IFileStorageService fileStorageService; + + @Resource + private EmployeeService employeeService; + + @Resource + private RoleEmployeeService roleEmployeeService; + + @Resource + private RoleMenuService roleMenuService; + + + /** + * 获取请求用户信息 + */ + @Cacheable(AdminCacheConst.Login.REQUEST_EMPLOYEE) + public RequestEmployee getRequestEmployee(Long requestEmployeeId ) { + if (requestEmployeeId == null) { + return null; + } + // 员工基本信息 + EmployeeEntity employeeEntity = employeeService.getById(requestEmployeeId); + if (employeeEntity == null) { + return null; + } + + return this.loadLoginInfo(employeeEntity); + } + + /** + * 获取登录的用户信息 + */ + @CachePut(value = AdminCacheConst.Login.REQUEST_EMPLOYEE, key = "#employeeEntity.employeeId") + public RequestEmployee loadLoginInfo(EmployeeEntity employeeEntity) { + // 基础信息 + RequestEmployee requestEmployee = SmartBeanUtil.copy(employeeEntity, RequestEmployee.class); + requestEmployee.setUserType(UserTypeEnum.ADMIN_EMPLOYEE); + + // 部门信息 + DepartmentVO department = departmentService.getDepartmentById(employeeEntity.getDepartmentId()); + requestEmployee.setDepartmentName(null == department ? StringConst.EMPTY : department.getDepartmentName()); + + // 头像信息 + String avatar = employeeEntity.getAvatar(); + if (StringUtils.isNotBlank(avatar)) { + ResponseDTO getFileUrl = fileStorageService.getFileUrl(avatar); + if (BooleanUtils.isTrue(getFileUrl.getOk())) { + requestEmployee.setAvatar(getFileUrl.getData()); + } + } + return requestEmployee; + } + + + /** + * 获取用户的权限(包含 角色列表、权限列表) + */ + @Cacheable(AdminCacheConst.Login.USER_PERMISSION) + public UserPermission getUserPermission(Long employeeId) { + if(null == employeeId){ + return null; + } + + return this.loadUserPermission(employeeId); + } + + /** + * 获取用户的权限(包含 角色列表、权限列表) + */ + @CachePut(AdminCacheConst.Login.USER_PERMISSION) + public UserPermission loadUserPermission(Long employeeId) { + UserPermission userPermission = new UserPermission(); + userPermission.setPermissionList(new ArrayList<>()); + userPermission.setRoleList(new ArrayList<>()); + + // 角色列表 + List roleList = roleEmployeeService.getRoleIdList(employeeId); + userPermission.getRoleList().addAll(roleList.stream().map(RoleVO::getRoleCode).collect(Collectors.toSet())); + + // 前端菜单和功能点清单 + EmployeeEntity employeeEntity = employeeService.getById(employeeId); + + List menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), employeeEntity.getAdministratorFlag()); + + // 权限列表 + HashSet permissionSet = new HashSet<>(); + for (MenuVO menu : menuAndPointsList) { + if (menu.getPermsType() == null) { + continue; + } + + String perms = menu.getApiPerms(); + if (StringUtils.isEmpty(perms)) { + continue; + } + //接口权限 + String[] split = perms.split(","); + permissionSet.addAll(Arrays.asList(split)); + } + userPermission.getPermissionList().addAll(permissionSet); + + return userPermission; + } + + + @CacheEvict(value = {AdminCacheConst.Login.USER_PERMISSION, AdminCacheConst.Login.REQUEST_EMPLOYEE}, allEntries = true) + public void clear(){ + + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java new file mode 100644 index 0000000..c5fa8c7 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java @@ -0,0 +1,487 @@ +package net.lab1024.sa.admin.module.system.login.service; + +import cn.dev33.satoken.stp.StpInterface; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.lang.UUID; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.extra.servlet.JakartaServletUtil; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.admin.module.system.department.service.DepartmentService; +import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; +import net.lab1024.sa.admin.module.system.employee.service.EmployeeService; +import net.lab1024.sa.admin.module.system.login.domain.LoginForm; +import net.lab1024.sa.admin.module.system.login.domain.LoginResultVO; +import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee; +import net.lab1024.sa.admin.module.system.login.manager.LoginManager; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO; +import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService; +import net.lab1024.sa.admin.module.system.role.service.RoleMenuService; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.constant.RequestHeaderConst; +import net.lab1024.sa.base.common.constant.StringConst; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.UserPermission; +import net.lab1024.sa.base.common.enumeration.UserTypeEnum; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartEnumUtil; +import net.lab1024.sa.base.common.util.SmartIpUtil; +import net.lab1024.sa.base.common.util.SmartStringUtil; +import net.lab1024.sa.base.constant.LoginDeviceEnum; +import net.lab1024.sa.base.constant.RedisKeyConst; +import net.lab1024.sa.base.module.support.apiencrypt.service.ApiEncryptService; +import net.lab1024.sa.base.module.support.captcha.CaptchaService; +import net.lab1024.sa.base.module.support.captcha.domain.CaptchaVO; +import net.lab1024.sa.base.module.support.config.ConfigKeyEnum; +import net.lab1024.sa.base.module.support.config.ConfigService; +import net.lab1024.sa.base.module.support.file.service.IFileStorageService; +import net.lab1024.sa.base.module.support.loginlog.LoginLogResultEnum; +import net.lab1024.sa.base.module.support.loginlog.LoginLogService; +import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogEntity; +import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogVO; +import net.lab1024.sa.base.module.support.mail.MailService; +import net.lab1024.sa.base.module.support.mail.constant.MailTemplateCodeEnum; +import net.lab1024.sa.base.module.support.redis.RedisService; +import net.lab1024.sa.base.module.support.securityprotect.domain.LoginFailEntity; +import net.lab1024.sa.base.module.support.securityprotect.service.Level3ProtectConfigService; +import net.lab1024.sa.base.module.support.securityprotect.service.SecurityLoginService; +import net.lab1024.sa.base.module.support.securityprotect.service.SecurityPasswordService; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 登录 + * + * @Author 1024创新实验室: 卓大 + * @Date 2025-05-03 22:56:34 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Slf4j +@Service +public class LoginService implements StpInterface { + + /** + * 万能密码的 sa token loginId 前缀 + */ + private static final String SUPER_PASSWORD_LOGIN_ID_PREFIX = "S"; + + @Resource + private EmployeeService employeeService; + + @Resource + private DepartmentService departmentService; + + @Resource + private CaptchaService captchaService; + + @Resource + private ConfigService configService; + + @Resource + private LoginLogService loginLogService; + + @Resource + private RoleEmployeeService roleEmployeeService; + + @Resource + private RoleMenuService roleMenuService; + + @Resource + private SecurityLoginService securityLoginService; + + @Resource + private SecurityPasswordService protectPasswordService; + + @Resource + private IFileStorageService fileStorageService; + + @Resource + private ApiEncryptService apiEncryptService; + + @Resource + private Level3ProtectConfigService level3ProtectConfigService; + + @Resource + private MailService mailService; + + @Resource + private RedisService redisService; + + @Resource + private LoginManager loginManager; + + /** + * 获取验证码 + */ + public ResponseDTO getCaptcha() { + return ResponseDTO.ok(captchaService.generateCaptcha()); + } + + /** + * 员工登陆 + * + * @return 返回用户登录信息 + */ + public ResponseDTO login(LoginForm loginForm, String ip, String userAgent) { + + LoginDeviceEnum loginDeviceEnum = SmartEnumUtil.getEnumByValue(loginForm.getLoginDevice(), LoginDeviceEnum.class); + if (loginDeviceEnum == null) { + return ResponseDTO.userErrorParam("登录设备暂不支持!"); + } + + // 校验 图形验证码 + ResponseDTO checkCaptcha = captchaService.checkCaptcha(loginForm); + if (!checkCaptcha.getOk()) { + return ResponseDTO.error(UserErrorCode.PARAM_ERROR, checkCaptcha.getMsg()); + } + + // 验证登录名 + EmployeeEntity employeeEntity = employeeService.getByLoginName(loginForm.getLoginName()); + if (null == employeeEntity) { + return ResponseDTO.userErrorParam("登录名或密码错误!"); + } + + // 验证账号状态 + if (employeeEntity.getDeletedFlag()) { + saveLoginLog(employeeEntity, ip, userAgent, "账号已删除", LoginLogResultEnum.LOGIN_FAIL, loginDeviceEnum); + return ResponseDTO.userErrorParam("您的账号已被删除,请联系工作人员!"); + } + + if (employeeEntity.getDisabledFlag()) { + saveLoginLog(employeeEntity, ip, userAgent, "账号已禁用", LoginLogResultEnum.LOGIN_FAIL, loginDeviceEnum); + return ResponseDTO.userErrorParam("您的账号已被禁用,请联系工作人员!"); + } + + // 解密前端加密的密码 + String requestPassword = apiEncryptService.decrypt(loginForm.getPassword()); + + // 验证密码 是否为万能密码 + String superPassword = configService.getConfigValue(ConfigKeyEnum.SUPER_PASSWORD); + boolean superPasswordFlag = superPassword.equals(requestPassword); + + // 校验双因子登录 + ResponseDTO validateEmailCode = validateEmailCode(loginForm, employeeEntity, superPasswordFlag); + if (!validateEmailCode.getOk()) { + return ResponseDTO.error(validateEmailCode); + } + + // 万能密码特殊操作 + if (superPasswordFlag) { + + // 对于万能密码:受限制sa token 要求loginId唯一,万能密码只能插入一段uuid + String saTokenLoginId = SUPER_PASSWORD_LOGIN_ID_PREFIX + StringConst.COLON + UUID.randomUUID().toString().replace("-", "") + StringConst.COLON + employeeEntity.getEmployeeId(); + // 万能密码登录只能登录30分钟 + StpUtil.login(saTokenLoginId, 1800); + + } else { + + // 按照等保登录要求,进行登录失败次数校验 + ResponseDTO loginFailEntityResponseDTO = securityLoginService.checkLogin(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE); + if (!loginFailEntityResponseDTO.getOk()) { + return ResponseDTO.error(loginFailEntityResponseDTO); + } + + // 密码错误 + if (!SecurityPasswordService.matchesPwd(requestPassword, employeeEntity.getLoginPwd())) { + // 记录登录失败 + saveLoginLog(employeeEntity, ip, userAgent, "密码错误", LoginLogResultEnum.LOGIN_FAIL, loginDeviceEnum); + // 记录等级保护次数 + String msg = securityLoginService.recordLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE, employeeEntity.getLoginName(), loginFailEntityResponseDTO.getData()); + return msg == null ? ResponseDTO.userErrorParam("登录名或密码错误!") : ResponseDTO.error(UserErrorCode.LOGIN_FAIL_WILL_LOCK, msg); + } + + String saTokenLoginId = UserTypeEnum.ADMIN_EMPLOYEE.getValue() + StringConst.COLON + employeeEntity.getEmployeeId(); + + // 登录 + StpUtil.login(saTokenLoginId, String.valueOf(loginDeviceEnum.getDesc())); + + // 移除邮箱验证码 + deleteEmailCode(employeeEntity.getEmployeeId()); + } + + // 获取员工信息 + RequestEmployee requestEmployee = loginManager.loadLoginInfo(employeeEntity); + + // 移除登录失败 + securityLoginService.removeLoginFail(employeeEntity.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE); + + // 获取登录结果信息 + String token = StpUtil.getTokenValue(); + LoginResultVO loginResultVO = getLoginResult(requestEmployee, token); + + //保存登录记录 + saveLoginLog(employeeEntity, ip, userAgent, superPasswordFlag ? "万能密码登录" : StringConst.EMPTY, LoginLogResultEnum.LOGIN_SUCCESS, loginDeviceEnum); + + // 设置 token + loginResultVO.setToken(token); + + // 更新用户权限 + loginManager.loadUserPermission(employeeEntity.getEmployeeId()); + + return ResponseDTO.ok(loginResultVO); + } + + + /** + * 获取登录结果信息 + */ + public LoginResultVO getLoginResult(RequestEmployee requestEmployee, String token) { + + // 基础信息 + LoginResultVO loginResultVO = SmartBeanUtil.copy(requestEmployee, LoginResultVO.class); + + // 前端菜单和功能点清单 + List roleList = roleEmployeeService.getRoleIdList(requestEmployee.getEmployeeId()); + List menuAndPointsList = roleMenuService.getMenuList(roleList.stream().map(RoleVO::getRoleId).collect(Collectors.toList()), requestEmployee.getAdministratorFlag()); + loginResultVO.setMenuList(menuAndPointsList); + + // 上次登录信息 + LoginLogVO loginLogVO = loginLogService.queryLastByUserId(requestEmployee.getEmployeeId(), UserTypeEnum.ADMIN_EMPLOYEE, LoginLogResultEnum.LOGIN_SUCCESS); + if (loginLogVO != null) { + loginResultVO.setLastLoginIp(loginLogVO.getLoginIp()); + loginResultVO.setLastLoginIpRegion(loginLogVO.getLoginIpRegion()); + loginResultVO.setLastLoginTime(loginLogVO.getCreateTime()); + loginResultVO.setLastLoginUserAgent(loginLogVO.getUserAgent()); + } + + // 是否需要强制修改密码 + boolean needChangePasswordFlag = protectPasswordService.checkNeedChangePassword(requestEmployee.getUserType().getValue(), requestEmployee.getUserId()); + loginResultVO.setNeedUpdatePwdFlag(needChangePasswordFlag); + + // 万能密码登录,则不需要设置强制修改密码 + String loginIdByToken = (String) StpUtil.getLoginIdByToken(token); + if (loginIdByToken != null && loginIdByToken.startsWith(SUPER_PASSWORD_LOGIN_ID_PREFIX)) { + loginResultVO.setNeedUpdatePwdFlag(false); + } + + return loginResultVO; + } + + + /** + * 根据登陆token 获取员请求工信息 + */ + public RequestEmployee getLoginEmployee(String loginId, HttpServletRequest request) { + if (loginId == null) { + return null; + } + + Long requestEmployeeId = getEmployeeIdByLoginId(loginId); + if (requestEmployeeId == null) { + return null; + } + + RequestEmployee requestEmployee = loginManager.getRequestEmployee(requestEmployeeId); + + // 更新请求ip和user agent + requestEmployee.setUserAgent(JakartaServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT)); + requestEmployee.setIp(JakartaServletUtil.getClientIP(request)); + + return requestEmployee; + } + + /** + * 根据 loginId 获取 员工id + */ + Long getEmployeeIdByLoginId(String loginId) { + + if (loginId == null) { + return null; + } + + try { + // 如果是 万能密码 登录的用户 + String employeeIdStr = null; + if (loginId.startsWith(SUPER_PASSWORD_LOGIN_ID_PREFIX)) { + employeeIdStr = loginId.split(StringConst.COLON)[2]; + } else { + employeeIdStr = loginId.substring(2); + } + + return Long.parseLong(employeeIdStr); + } catch (Exception e) { + log.error("loginId parse error , loginId : {}", loginId, e); + return null; + } + } + + + /** + * 退出登录 + */ + public ResponseDTO logout(RequestUser requestUser) { + + // sa token 登出 + StpUtil.logout(); + + // 清空登录信息缓存 + loginManager.clear(); + + //保存登出日志 + LoginLogEntity loginEntity = LoginLogEntity.builder() + .userId(requestUser.getUserId()) + .userType(requestUser.getUserType().getValue()) + .userName(requestUser.getUserName()) + .userAgent(requestUser.getUserAgent()) + .loginIp(requestUser.getIp()) + .loginIpRegion(SmartIpUtil.getRegion(requestUser.getIp())) + .loginResult(LoginLogResultEnum.LOGIN_OUT.getValue()) + .createTime(LocalDateTime.now()) + .build(); + loginLogService.log(loginEntity); + + return ResponseDTO.ok(); + } + + /** + * 保存登录日志 + */ + private void saveLoginLog(EmployeeEntity employeeEntity, String ip, String userAgent, String remark, LoginLogResultEnum result, LoginDeviceEnum loginDeviceEnum) { + LoginLogEntity loginEntity = LoginLogEntity.builder() + .userId(employeeEntity.getEmployeeId()) + .userType(UserTypeEnum.ADMIN_EMPLOYEE.getValue()) + .userName(employeeEntity.getActualName()) + .userAgent(userAgent) + .loginIp(ip) + .loginIpRegion(SmartIpUtil.getRegion(ip)) + .remark(remark) + .loginDevice(loginDeviceEnum.getDesc()) + .loginResult(result.getValue()) + .createTime(LocalDateTime.now()) + .build(); + loginLogService.log(loginEntity); + } + + + @Override + public List getPermissionList(Object loginId, String loginType) { + Long employeeId = this.getEmployeeIdByLoginId((String) loginId); + if (employeeId == null) { + return Collections.emptyList(); + } + + UserPermission userPermission = loginManager.getUserPermission(employeeId); + return userPermission.getPermissionList(); + } + + @Override + public List getRoleList(Object loginId, String loginType) { + Long employeeId = this.getEmployeeIdByLoginId((String) loginId); + if (employeeId == null) { + return Collections.emptyList(); + } + + UserPermission userPermission = loginManager.getUserPermission(employeeId); + return userPermission.getRoleList(); + } + + + /** + * 发送 邮箱 验证码 + */ + public ResponseDTO sendEmailCode(String loginName) { + + // 开启双因子登录 + if (!level3ProtectConfigService.isTwoFactorLoginEnabled()) { + return ResponseDTO.userErrorParam("无需使用邮箱验证码"); + } + + // 验证登录名 + EmployeeEntity employeeEntity = employeeService.getByLoginName(loginName); + if (null == employeeEntity) { + return ResponseDTO.ok(); + } + + // 验证账号状态 + if (employeeEntity.getDeletedFlag()) { + return ResponseDTO.userErrorParam("您的账号已被删除,请联系工作人员!"); + } + + if (employeeEntity.getDisabledFlag()) { + return ResponseDTO.userErrorParam("您的账号已被禁用,请联系工作人员!"); + } + + String mail = employeeEntity.getEmail(); + if (SmartStringUtil.isBlank(mail)) { + return ResponseDTO.userErrorParam("您暂未配置邮箱地址,请联系管理员配置邮箱"); + } + + // 校验验证码发送时间,60秒内不能重复发生 + String redisVerificationCodeKey = redisService.generateRedisKey(RedisKeyConst.Support.LOGIN_VERIFICATION_CODE, UserTypeEnum.ADMIN_EMPLOYEE.getValue() + RedisKeyConst.SEPARATOR + employeeEntity.getEmployeeId()); + String emailCode = redisService.get(redisVerificationCodeKey); + long sendCodeTimeMills = -1; + if (!SmartStringUtil.isEmpty(emailCode)) { + sendCodeTimeMills = NumberUtil.parseLong(emailCode.split(StringConst.UNDERLINE)[1]); + } + + if (System.currentTimeMillis() - sendCodeTimeMills < 60 * 1000) { + return ResponseDTO.userErrorParam("邮箱验证码已发送,一分钟内请勿重复发送"); + } + + //生成验证码 + long currentTimeMillis = System.currentTimeMillis(); + String verificationCode = RandomUtil.randomNumbers(4); + redisService.set(redisVerificationCodeKey, verificationCode + StringConst.UNDERLINE + currentTimeMillis, 300); + + // 发送邮件验证码 + HashMap mailParams = new HashMap<>(); + mailParams.put("code", verificationCode); + return mailService.sendMail(MailTemplateCodeEnum.LOGIN_VERIFICATION_CODE, mailParams, Collections.singletonList(employeeEntity.getEmail())); + } + + + /** + * 校验邮箱验证码 + */ + private ResponseDTO validateEmailCode(LoginForm loginForm, EmployeeEntity employeeEntity, boolean superPasswordFlag) { + // 万能密码则不校验 + if (superPasswordFlag) { + return ResponseDTO.ok(); + } + + // 未开启双因子登录 + if (!level3ProtectConfigService.isTwoFactorLoginEnabled()) { + return ResponseDTO.ok(); + } + + if (SmartStringUtil.isEmpty(loginForm.getEmailCode())) { + return ResponseDTO.userErrorParam("请输入邮箱验证码"); + } + + // 校验验证码 + String redisVerificationCodeKey = redisService.generateRedisKey(RedisKeyConst.Support.LOGIN_VERIFICATION_CODE, UserTypeEnum.ADMIN_EMPLOYEE.getValue() + RedisKeyConst.SEPARATOR + employeeEntity.getEmployeeId()); + String emailCode = redisService.get(redisVerificationCodeKey); + if (SmartStringUtil.isEmpty(emailCode)) { + return ResponseDTO.userErrorParam("邮箱验证码已失效,请重新发送"); + } + + if (!emailCode.split(StringConst.UNDERLINE)[0].equals(loginForm.getEmailCode().trim())) { + return ResponseDTO.userErrorParam("邮箱验证码错误,请重新填写"); + } + + return ResponseDTO.ok(); + } + + /** + * 移除邮箱验证码 + */ + private void deleteEmailCode(Long employeeId) { + String redisVerificationCodeKey = redisService.generateRedisKey(RedisKeyConst.Support.LOGIN_VERIFICATION_CODE, UserTypeEnum.ADMIN_EMPLOYEE.getValue() + RedisKeyConst.SEPARATOR + employeeId); + redisService.delete(redisVerificationCodeKey); + } + + public void clearLoginEmployeeCache(Long employeeId) { + loginManager.clear(); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/constant/MenuPermsTypeEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/constant/MenuPermsTypeEnum.java new file mode 100644 index 0000000..724820b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/constant/MenuPermsTypeEnum.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.system.menu.constant; + + +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 权限类型 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public enum MenuPermsTypeEnum implements BaseEnum { + /** + * sa-token + */ + SA_TOKEN(1, "Sa-Token模式"), + + ; + + private final Integer value; + + private final String desc; + + + MenuPermsTypeEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + @Override + public Integer getValue() { + return value; + } + + @Override + public String getDesc() { + return desc; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/constant/MenuTypeEnum.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/constant/MenuTypeEnum.java new file mode 100644 index 0000000..c447443 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/constant/MenuTypeEnum.java @@ -0,0 +1,48 @@ +package net.lab1024.sa.admin.module.system.menu.constant; + + +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 菜单类型枚举 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +public enum MenuTypeEnum implements BaseEnum { + /** + * 目录 + */ + CATALOG(1, "目录"), + /** + * 菜单 + */ + MENU(2, "菜单"), + /** + * 功能点 + */ + POINTS(3, "功能点"); + + private final Integer value; + + private final String desc; + + + MenuTypeEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + @Override + public Integer getValue() { + return value; + } + + @Override + public String getDesc() { + return desc; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/controller/MenuController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/controller/MenuController.java new file mode 100644 index 0000000..590a400 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/controller/MenuController.java @@ -0,0 +1,83 @@ +package net.lab1024.sa.admin.module.system.menu.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.menu.domain.form.MenuAddForm; +import net.lab1024.sa.admin.module.system.menu.domain.form.MenuUpdateForm; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuTreeVO; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO; +import net.lab1024.sa.admin.module.system.menu.service.MenuService; +import net.lab1024.sa.base.common.domain.RequestUrlVO; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 菜单 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_MENU) +public class MenuController { + + @Resource + private MenuService menuService; + + @Operation(summary = "添加菜单 @author 卓大") + @PostMapping("/menu/add") + @SaCheckPermission("system:menu:add") + public ResponseDTO addMenu(@RequestBody @Valid MenuAddForm menuAddForm) { + menuAddForm.setCreateUserId(SmartRequestUtil.getRequestUserId()); + return menuService.addMenu(menuAddForm); + } + + @Operation(summary = "更新菜单 @author 卓大") + @PostMapping("/menu/update") + @SaCheckPermission("system:menu:update") + public ResponseDTO updateMenu(@RequestBody @Valid MenuUpdateForm menuUpdateForm) { + menuUpdateForm.setUpdateUserId(SmartRequestUtil.getRequestUserId()); + return menuService.updateMenu(menuUpdateForm); + } + + @Operation(summary = "批量删除菜单 @author 卓大") + @GetMapping("/menu/batchDelete") + @SaCheckPermission("system:menu:batchDelete") + public ResponseDTO batchDeleteMenu(@RequestParam("menuIdList") List menuIdList) { + return menuService.batchDeleteMenu(menuIdList, SmartRequestUtil.getRequestUserId()); + } + + @Operation(summary = "查询菜单列表 @author 卓大") + @GetMapping("/menu/query") + public ResponseDTO> queryMenuList() { + return ResponseDTO.ok(menuService.queryMenuList(null)); + } + + @Operation(summary = "查询菜单详情 @author 卓大") + @GetMapping("/menu/detail/{menuId}") + public ResponseDTO getMenuDetail(@PathVariable Long menuId) { + return menuService.getMenuDetail(menuId); + } + + @Operation(summary = "查询菜单树 @author 卓大") + @GetMapping("/menu/tree") + public ResponseDTO> queryMenuTree(@RequestParam("onlyMenu") Boolean onlyMenu) { + return menuService.queryMenuTree(onlyMenu); + } + + @Operation(summary = "获取所有请求路径 @author 卓大") + @GetMapping("/menu/auth/url") + public ResponseDTO> getAuthUrl() { + return menuService.getAuthUrl(); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/dao/MenuDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/dao/MenuDao.java new file mode 100644 index 0000000..e2cd1b5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/dao/MenuDao.java @@ -0,0 +1,96 @@ +package net.lab1024.sa.admin.module.system.menu.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; +import net.lab1024.sa.admin.module.system.menu.domain.entity.MenuEntity; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO; + +import java.util.List; + +/** + * 菜单 dao + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface MenuDao extends BaseMapper { + + /** + * 根据名称查询同一级下的菜单 + * + * @param menuName 菜单名 + * @param parentId 父级id + * @param deletedFlag 是否删除 + */ + MenuEntity getByMenuName(@Param("menuName") String menuName, @Param("parentId") Long parentId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 根据前端权限字符串查询菜单 + * + * @param webPerms 前端权限字符串 + * @param deletedFlag 是否删除 + */ + MenuEntity getByWebPerms(@Param("webPerms") String webPerms, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 根据菜单ID删除菜单(逻辑删除) + * + * @param menuIdList 菜单id集合 + * @param updateUserId 操作人id + * @param deletedFlag 是否删除 + */ + void deleteByMenuIdList(@Param("menuIdList") List menuIdList, @Param("updateUserId") Long updateUserId, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 查询菜单列表 + * + * @param deletedFlag 是否删除 + * @param disabledFlag 是否禁用 + * @param menuTypeList 菜单类型集合 + */ + List queryMenuList(@Param("deletedFlag") Boolean deletedFlag, @Param("disabledFlag") Boolean disabledFlag, @Param("menuTypeList") List menuTypeList); + + + /** + * 根据菜单ID 查询功能点列表 + * + * @param menuId 菜单id + * @param menuType 菜单类型 + * @param deletedFlag 删除标记 + */ + List getPointListByMenuId(@Param("menuId") Long menuId, @Param("menuType") Integer menuType, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 根据员工ID查询菜单列表 + * + * @param deletedFlag 是否删除 + * @param disabledFlag 禁用标识 + * @param employeeId 员工id + */ + List queryMenuByEmployeeId(@Param("deletedFlag") Boolean deletedFlag, + @Param("disabledFlag") Boolean disabledFlag, + @Param("employeeId") Long employeeId); + + /** + * 根据菜单类型查询 + * + * @param menuType 菜单类型 + * @param deletedFlag 删除 + * @param disabledFlag 禁用 + */ + List queryMenuByType(@Param("menuType") Integer menuType, + @Param("deletedFlag") Boolean deletedFlag, + @Param("disabledFlag") Boolean disabledFlag); + + /** + * 查询孩子id + * + */ + List selectMenuIdByParentIdList(@Param("menuIdList") List menuIdList); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/entity/MenuEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/entity/MenuEntity.java new file mode 100644 index 0000000..2876eb6 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/entity/MenuEntity.java @@ -0,0 +1,136 @@ +package net.lab1024.sa.admin.module.system.menu.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import net.lab1024.sa.admin.module.system.menu.constant.MenuTypeEnum; + +import java.time.LocalDateTime; + +/** + * 菜单 表 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName(value = "t_smart_menu") +public class MenuEntity { + + /** + * 菜单ID + */ + @TableId(type = IdType.AUTO) + private Long menuId; + + /** + * 菜单名称 + */ + private String menuName; + + /** + * 类型 + * + * @see MenuTypeEnum + */ + private Integer menuType; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 显示顺序 + */ + private Integer sort; + + /** + * 路由地址 + */ + private String path; + + /** + * 组件路径 + */ + private String component; + + /** + * 是否为外链 + */ + private Boolean frameFlag; + + /** + * 外链地址 + */ + private String frameUrl; + + /** + * 是否缓存 + */ + private Boolean cacheFlag; + + /** + * 显示状态 + */ + private Boolean visibleFlag; + + /** + * 禁用状态 + */ + private Boolean disabledFlag; + + /** + * 后端权限字符串 + */ + private String apiPerms; + + /** + * 权限类型 + */ + private Integer permsType; + + /** + * 前端权限字符串 + */ + private String webPerms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 功能点关联菜单ID + */ + private Long contextMenuId; + + /** + * 删除状态 + */ + private Boolean deletedFlag; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 创建人 + */ + private Long createUserId; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 更新人 + */ + private Long updateUserId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuAddForm.java new file mode 100644 index 0000000..e80584b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuAddForm.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.system.menu.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 菜单 添加表单 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class MenuAddForm extends MenuBaseForm { + + @Schema(hidden = true) + private Long createUserId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuBaseForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuBaseForm.java new file mode 100644 index 0000000..d277267 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuBaseForm.java @@ -0,0 +1,81 @@ +package net.lab1024.sa.admin.module.system.menu.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.admin.module.system.menu.constant.MenuPermsTypeEnum; +import net.lab1024.sa.admin.module.system.menu.constant.MenuTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import org.hibernate.validator.constraints.Length; + +/** + * 菜单基础 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class MenuBaseForm { + + @Schema(description = "菜单名称") + @NotBlank(message = "菜单名称不能为空") + @Length(max = 30, message = "菜单名称最多30个字符") + private String menuName; + + @SchemaEnum(value = MenuTypeEnum.class, desc = "类型") + @CheckEnum(value = MenuTypeEnum.class, message = "类型错误") + private Integer menuType; + + @Schema(description = "父菜单ID 无上级可传0") + @NotNull(message = "父菜单ID不能为空") + private Long parentId; + + @Schema(description = "显示顺序") + private Integer sort; + + @Schema(description = "路由地址") + private String path; + + @Schema(description = "组件路径") + private String component; + + @Schema(description = "是否为外链") + @NotNull(message = "是否为外链不能为空") + private Boolean frameFlag; + + @Schema(description = "外链地址") + private String frameUrl; + + @Schema(description = "是否缓存") + @NotNull(message = "是否缓存不能为空") + private Boolean cacheFlag; + + @Schema(description = "显示状态") + @NotNull(message = "显示状态不能为空") + private Boolean visibleFlag; + + @Schema(description = "禁用状态") + @NotNull(message = "禁用状态不能为空") + private Boolean disabledFlag; + + @SchemaEnum(value = MenuPermsTypeEnum.class, desc = "权限类型 ") + @CheckEnum(value = MenuPermsTypeEnum.class, message = "权限类型") + private Integer permsType; + + @Schema(description = "前端权限字符串") + private String webPerms; + + @Schema(description = "后端端权限字符串") + private String apiPerms; + + @Schema(description = "菜单图标") + private String icon; + + @Schema(description = "功能点关联菜单ID") + private Long contextMenuId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuPointsOperateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuPointsOperateForm.java new file mode 100644 index 0000000..64a6ee2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuPointsOperateForm.java @@ -0,0 +1,43 @@ +package net.lab1024.sa.admin.module.system.menu.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import java.util.List; + +/** + * 菜单功能点操作Form + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class MenuPointsOperateForm { + + @Schema(description = "菜单ID") + private Long menuId; + + @Schema(description = "功能点名称") + @NotBlank(message = "功能点不能为空") + @Length(max = 30, message = "功能点最多30个字符") + private String menuName; + + @Schema(description = "禁用状态") + @NotNull(message = "禁用状态不能为空") + private Boolean disabledFlag; + + @Schema(description = "后端接口权限集合") + private List apiPermsList; + + @Schema(description = "权限字符串") + private String webPerms; + + @Schema(description = "功能点关联菜单ID") + private Long contextMenuId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuUpdateForm.java new file mode 100644 index 0000000..a8bf9df --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/form/MenuUpdateForm.java @@ -0,0 +1,25 @@ +package net.lab1024.sa.admin.module.system.menu.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 菜单 更新Form + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class MenuUpdateForm extends MenuBaseForm { + + @Schema(description = "菜单ID") + @NotNull(message = "菜单ID不能为空") + private Long menuId; + + @Schema(hidden = true) + private Long updateUserId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuSimpleTreeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuSimpleTreeVO.java new file mode 100644 index 0000000..8257d12 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuSimpleTreeVO.java @@ -0,0 +1,37 @@ +package net.lab1024.sa.admin.module.system.menu.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 简易的菜单VO + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class MenuSimpleTreeVO { + + @Schema(description = "菜单ID") + private Long menuId; + + @Schema(description = "菜单名称") + private String menuName; + + @Schema(description = "功能点关联菜单ID") + private Long contextMenuId; + + @Schema(description = "父级菜单ID") + private Long parentId; + + @Schema(description = "菜单类型") + private Integer menuType; + + @Schema(description = "子菜单") + private List children; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuTreeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuTreeVO.java new file mode 100644 index 0000000..5b69813 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuTreeVO.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.system.menu.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.util.List; + +/** + * 菜单 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class MenuTreeVO extends MenuVO{ + + @Schema(description = "菜单子集") + private List children; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuVO.java new file mode 100644 index 0000000..e809bda --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/domain/vo/MenuVO.java @@ -0,0 +1,35 @@ +package net.lab1024.sa.admin.module.system.menu.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.system.menu.domain.form.MenuBaseForm; + +import java.time.LocalDateTime; + +/** + * 菜单 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-06 22:04:37 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class MenuVO extends MenuBaseForm { + + @Schema(description = "菜单ID") + private Long menuId; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "创建人") + private Long createUserId; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "更新人") + private Long updateUserId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/service/MenuService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/service/MenuService.java new file mode 100644 index 0000000..53515ae --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/menu/service/MenuService.java @@ -0,0 +1,237 @@ +package net.lab1024.sa.admin.module.system.menu.service; + +import cn.hutool.core.collection.CollectionUtil; +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.menu.constant.MenuTypeEnum; +import net.lab1024.sa.admin.module.system.menu.dao.MenuDao; +import net.lab1024.sa.admin.module.system.menu.domain.entity.MenuEntity; +import net.lab1024.sa.admin.module.system.menu.domain.form.MenuAddForm; +import net.lab1024.sa.admin.module.system.menu.domain.form.MenuBaseForm; +import net.lab1024.sa.admin.module.system.menu.domain.form.MenuUpdateForm; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuTreeVO; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO; +import net.lab1024.sa.base.common.code.SystemErrorCode; +import net.lab1024.sa.base.common.domain.RequestUrlVO; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartStringUtil; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 菜单 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-08 22:15:09 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class MenuService { + + @Resource + private MenuDao menuDao; + + @Resource + private List authUrl; + + /** + * 添加菜单 + * + */ + public synchronized ResponseDTO addMenu(MenuAddForm menuAddForm) { + // 校验菜单名称 + if (this.validateMenuName(menuAddForm)) { + return ResponseDTO.userErrorParam("菜单名称已存在"); + } + // 校验前端权限字符串 + if (this.validateWebPerms(menuAddForm)) { + return ResponseDTO.userErrorParam("前端权限字符串已存在"); + } + MenuEntity menuEntity = SmartBeanUtil.copy(menuAddForm, MenuEntity.class); + menuDao.insert(menuEntity); + return ResponseDTO.ok(); + } + + /** + * 更新菜单 + * + */ + public synchronized ResponseDTO updateMenu(MenuUpdateForm menuUpdateForm) { + //校验菜单是否存在 + MenuEntity selectMenu = menuDao.selectById(menuUpdateForm.getMenuId()); + if (selectMenu == null) { + return ResponseDTO.userErrorParam("菜单不存在"); + } + if (selectMenu.getDeletedFlag()) { + return ResponseDTO.userErrorParam("菜单已被删除"); + } + //校验菜单名称 + if (this.validateMenuName(menuUpdateForm)) { + return ResponseDTO.userErrorParam("菜单名称已存在"); + } + // 校验前端权限字符串 + if (this.validateWebPerms(menuUpdateForm)) { + return ResponseDTO.userErrorParam("前端权限字符串已存在"); + } + if (menuUpdateForm.getMenuId().equals(menuUpdateForm.getParentId())) { + return ResponseDTO.userErrorParam("上级菜单不能为自己"); + } + MenuEntity menuEntity = SmartBeanUtil.copy(menuUpdateForm, MenuEntity.class); + menuDao.updateById(menuEntity); + return ResponseDTO.ok(); + } + + + /** + * 批量删除菜单 + * + */ + public synchronized ResponseDTO batchDeleteMenu(List menuIdList, Long employeeId) { + if (CollectionUtils.isEmpty(menuIdList)) { + return ResponseDTO.userErrorParam("所选菜单不能为空"); + } + menuDao.deleteByMenuIdList(menuIdList, employeeId, Boolean.TRUE); + //孩子节点也需要删除 + this.recursiveDeleteChildren(menuIdList, employeeId); + return ResponseDTO.ok(); + } + + private void recursiveDeleteChildren(List menuIdList, Long employeeId) { + List childrenMenuIdList = menuDao.selectMenuIdByParentIdList(menuIdList); + if (CollectionUtil.isEmpty(childrenMenuIdList)) { + return; + } + menuDao.deleteByMenuIdList(childrenMenuIdList, employeeId, Boolean.TRUE); + recursiveDeleteChildren(childrenMenuIdList, employeeId); + } + + /** + * 校验菜单名称 + * + */ + public Boolean validateMenuName(T menuDTO) { + MenuEntity menu = menuDao.getByMenuName(menuDTO.getMenuName(), menuDTO.getParentId(), Boolean.FALSE); + if (menuDTO instanceof MenuAddForm) { + return menu != null; + } + if (menuDTO instanceof MenuUpdateForm) { + Long menuId = ((MenuUpdateForm) menuDTO).getMenuId(); + return menu != null && menu.getMenuId().longValue() != menuId.longValue(); + } + return true; + } + + /** + * 校验前端权限字符串 + * + * @return true 重复 false 未重复 + */ + public Boolean validateWebPerms(T menuDTO) { + if(SmartStringUtil.isEmpty(menuDTO.getWebPerms())){ + return false; + } + + MenuEntity menu = menuDao.getByWebPerms(menuDTO.getWebPerms(), Boolean.FALSE); + if (menuDTO instanceof MenuAddForm) { + return menu != null; + } + if (menuDTO instanceof MenuUpdateForm) { + Long menuId = ((MenuUpdateForm) menuDTO).getMenuId(); + return menu != null && menu.getMenuId().longValue() != menuId.longValue(); + } + return true; + } + + /** + * 查询菜单列表 + * + */ + public List queryMenuList(Boolean disabledFlag) { + List menuVOList = menuDao.queryMenuList(Boolean.FALSE, disabledFlag, null); + //根据ParentId进行分组 + Map> parentMap = menuVOList.stream().collect(Collectors.groupingBy(MenuVO::getParentId, Collectors.toList())); + return this.filterNoParentMenu(parentMap, NumberUtils.LONG_ZERO); + } + + /** + * 过滤没有上级菜单的菜单列表 + * + */ + private List filterNoParentMenu(Map> parentMap, Long parentId) { + // 获取本级菜单树List + List res = parentMap.getOrDefault(parentId, Lists.newArrayList()); + List childMenu = Lists.newArrayList(); + // 循环遍历下级菜单 + res.forEach(e -> { + List menuList = this.filterNoParentMenu(parentMap, e.getMenuId()); + childMenu.addAll(menuList); + }); + res.addAll(childMenu); + return res; + } + + /** + * 查询菜单树 + * + * @param onlyMenu 不查询功能点 + */ + public ResponseDTO> queryMenuTree(Boolean onlyMenu) { + List menuTypeList = Lists.newArrayList(); + if (onlyMenu) { + menuTypeList = Lists.newArrayList(MenuTypeEnum.CATALOG.getValue(), MenuTypeEnum.MENU.getValue()); + } + List menuVOList = menuDao.queryMenuList(Boolean.FALSE, null, menuTypeList); + //根据ParentId进行分组 + Map> parentMap = menuVOList.stream().collect(Collectors.groupingBy(MenuVO::getParentId, Collectors.toList())); + List menuTreeVOList = this.buildMenuTree(parentMap, NumberUtils.LONG_ZERO); + return ResponseDTO.ok(menuTreeVOList); + } + + /** + * 构建菜单树 + * + */ + List buildMenuTree(Map> parentMap, Long parentId) { + // 获取本级菜单树List + List res = parentMap.getOrDefault(parentId, Lists.newArrayList()).stream() + .map(e -> SmartBeanUtil.copy(e, MenuTreeVO.class)).collect(Collectors.toList()); + // 循环遍历下级菜单 + res.forEach(e -> { + e.setChildren(this.buildMenuTree(parentMap, e.getMenuId())); + }); + return res; + } + + /** + * 查询菜单详情 + * + */ + public ResponseDTO getMenuDetail(Long menuId) { + //校验菜单是否存在 + MenuEntity selectMenu = menuDao.selectById(menuId); + if (selectMenu == null) { + return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "菜单不存在"); + } + if (selectMenu.getDeletedFlag()) { + return ResponseDTO.error(SystemErrorCode.SYSTEM_ERROR, "菜单已被删除"); + } + MenuVO menuVO = SmartBeanUtil.copy(selectMenu, MenuVO.class); + return ResponseDTO.ok(menuVO); + } + + /** + * 获取系统所有请求路径 + */ + public ResponseDTO> getAuthUrl() { + return ResponseDTO.ok(authUrl); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/message/AdminMessageController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/message/AdminMessageController.java new file mode 100644 index 0000000..40922e2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/message/AdminMessageController.java @@ -0,0 +1,54 @@ +package net.lab1024.sa.admin.module.system.message; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.ValidateList; +import net.lab1024.sa.base.module.support.message.domain.MessageQueryForm; +import net.lab1024.sa.base.module.support.message.domain.MessageSendForm; +import net.lab1024.sa.base.module.support.message.domain.MessageVO; +import net.lab1024.sa.base.module.support.message.service.MessageService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + + +/** + * 后管 消息路由 + * + * @author: 卓大 + * @date: 2025/04/09 20:55 + */ +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_MESSAGE) +@RestController +public class AdminMessageController { + + @Autowired + private MessageService messageService; + + @Operation(summary = "通知消息-新建 @author 卓大") + @PostMapping("/message/sendMessages") + @SaCheckPermission("system:message:send") + public ResponseDTO sendMessages(@RequestBody @Valid ValidateList messageList) { + messageService.sendMessage(messageList); + return ResponseDTO.ok(); + } + + @Operation(summary = "通知消息-分页查询 @author 卓大") + @PostMapping("/message/query") + @SaCheckPermission("system:message:query") + public ResponseDTO> query(@RequestBody @Valid MessageQueryForm queryForm) { + return ResponseDTO.ok(messageService.query(queryForm)); + } + + @Operation(summary = "通知消息-删除 @author 卓大") + @GetMapping("/message/delete/{messageId}") + @SaCheckPermission("system:message:delete") + public ResponseDTO delete(@PathVariable Long messageId) { + return messageService.delete(messageId); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/controller/PositionController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/controller/PositionController.java new file mode 100644 index 0000000..de1108b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/controller/PositionController.java @@ -0,0 +1,71 @@ +package net.lab1024.sa.admin.module.system.position.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionAddForm; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionQueryForm; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionUpdateForm; +import net.lab1024.sa.admin.module.system.position.domain.vo.PositionVO; +import net.lab1024.sa.admin.module.system.position.service.PositionService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.ValidateList; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 职务表 Controller + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_POSITION) +public class PositionController { + + @Resource + private PositionService positionService; + + @Operation(summary = "分页查询 @author kaiyun") + @PostMapping("/position/queryPage") + public ResponseDTO> queryPage(@RequestBody @Valid PositionQueryForm queryForm) { + return ResponseDTO.ok(positionService.queryPage(queryForm)); + } + + @Operation(summary = "添加 @author kaiyun") + @PostMapping("/position/add") + public ResponseDTO add(@RequestBody @Valid PositionAddForm addForm) { + return positionService.add(addForm); + } + + @Operation(summary = "更新 @author kaiyun") + @PostMapping("/position/update") + public ResponseDTO update(@RequestBody @Valid PositionUpdateForm updateForm) { + return positionService.update(updateForm); + } + + @Operation(summary = "批量删除 @author kaiyun") + @PostMapping("/position/batchDelete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return positionService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author kaiyun") + @GetMapping("/position/delete/{positionId}") + public ResponseDTO batchDelete(@PathVariable Long positionId) { + return positionService.delete(positionId); + } + + + @Operation(summary = "不分页查询 @author kaiyun") + @GetMapping("/position/queryList") + public ResponseDTO> queryList() { + return ResponseDTO.ok(positionService.queryList()); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/dao/PositionDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/dao/PositionDao.java new file mode 100644 index 0000000..5fd307a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/dao/PositionDao.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.system.position.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.system.position.domain.entity.PositionEntity; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionQueryForm; +import net.lab1024.sa.admin.module.system.position.domain.vo.PositionVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 职务表 Dao + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Mapper +public interface PositionDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") PositionQueryForm queryForm); + + + /** + * 查询 + * @param deletedFlag + * @return + */ + List queryList(@Param("deletedFlag") Boolean deletedFlag); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/entity/PositionEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/entity/PositionEntity.java new file mode 100644 index 0000000..3b0fd19 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/entity/PositionEntity.java @@ -0,0 +1,61 @@ +package net.lab1024.sa.admin.module.system.position.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.time.LocalDateTime; + +import lombok.Data; + +/** + * 职务表 实体类 + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +@TableName("t_smart_position") +public class PositionEntity { + + /** + * 职务ID + */ + @TableId(type = IdType.AUTO) + private Long positionId; + + /** + * 职务名称 + */ + private String positionName; + + /** + * 职级 + */ + private String positionLevel; + + /** + * 排序 + */ + private Integer sort; + + /** + * 备注 + */ + private String remark; + + private Boolean deletedFlag; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionAddForm.java new file mode 100644 index 0000000..7aa0808 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionAddForm.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.module.system.position.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 职务表 新建表单 + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +public class PositionAddForm { + + @Schema(description = "职务名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "职务名称 不能为空") + private String positionName; + + @Schema(description = "职级") + private String positionLevel; + + @Schema(description = "排序") + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionQueryForm.java new file mode 100644 index 0000000..c6b7155 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionQueryForm.java @@ -0,0 +1,23 @@ +package net.lab1024.sa.admin.module.system.position.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 职务表 分页查询表单 + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +public class PositionQueryForm extends PageParam{ + + @Schema(description = "关键字查询") + private String keywords; + + @Schema(hidden = true) + private Boolean deletedFlag; +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionUpdateForm.java new file mode 100644 index 0000000..bcad625 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionUpdateForm.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.system.position.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 职务表 更新表单 + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +public class PositionUpdateForm extends PositionAddForm { + + @Schema(description = "职务ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "职务ID 不能为空") + private Long positionId; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/vo/PositionVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/vo/PositionVO.java new file mode 100644 index 0000000..05783ac --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/vo/PositionVO.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.system.position.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 职务表 列表VO + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +public class PositionVO { + + + @Schema(description = "职务ID") + private Long positionId; + + @Schema(description = "职务名称") + private String positionName; + + @Schema(description = "职级") + private String positionLevel; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/manager/PositionManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/manager/PositionManager.java new file mode 100644 index 0000000..1759de8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/manager/PositionManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.system.position.manager; + +import net.lab1024.sa.admin.module.system.position.dao.PositionDao; +import net.lab1024.sa.admin.module.system.position.domain.entity.PositionEntity; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 职务表 Manager + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ +@Service +public class PositionManager extends ServiceImpl { + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/service/PositionService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/service/PositionService.java new file mode 100644 index 0000000..88de6b2 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/service/PositionService.java @@ -0,0 +1,105 @@ +package net.lab1024.sa.admin.module.system.position.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.position.dao.PositionDao; +import net.lab1024.sa.admin.module.system.position.domain.entity.PositionEntity; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionAddForm; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionQueryForm; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionUpdateForm; +import net.lab1024.sa.admin.module.system.position.domain.vo.PositionVO; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * 职务表 Service + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Service +public class PositionService { + + @Resource + private PositionDao positionDao; + + /** + * 分页查询 + * + * @param queryForm + * @return + */ + public PageResult queryPage(PositionQueryForm queryForm) { + queryForm.setDeletedFlag(Boolean.FALSE); + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = positionDao.queryPage(page, queryForm); + PageResult pageResult = SmartPageUtil.convert2PageResult(page, list); + return pageResult; + } + + /** + * 添加 + */ + public ResponseDTO add(PositionAddForm addForm) { + PositionEntity positionEntity = SmartBeanUtil.copy(addForm, PositionEntity.class); + positionDao.insert(positionEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + * @param updateForm + * @return + */ + public ResponseDTO update(PositionUpdateForm updateForm) { + PositionEntity positionEntity = SmartBeanUtil.copy(updateForm, PositionEntity.class); + positionDao.updateById(positionEntity); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + * + * @param idList + * @return + */ + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)){ + return ResponseDTO.ok(); + } + + positionDao.deleteBatchIds(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + */ + public ResponseDTO delete(Long positionId) { + if (null == positionId){ + return ResponseDTO.ok(); + } + + positionDao.deleteById(positionId); + return ResponseDTO.ok(); + } + + /** + * 分页查询 + * + * @return + */ + public List queryList() { + List list = positionDao.queryList(Boolean.FALSE); + return list; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleController.java new file mode 100644 index 0000000..40448bb --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleController.java @@ -0,0 +1,67 @@ +package net.lab1024.sa.admin.module.system.role.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleAddForm; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleUpdateForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO; +import net.lab1024.sa.admin.module.system.role.service.RoleService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 角色 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-12-14 19:40:28 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_ROLE) +public class RoleController { + + @Resource + private RoleService roleService; + + @Operation(summary = "添加角色 @author 卓大") + @PostMapping("/role/add") + @SaCheckPermission("system:role:add") + public ResponseDTO addRole(@Valid @RequestBody RoleAddForm roleAddForm) { + return roleService.addRole(roleAddForm); + } + + @Operation(summary = "删除角色 @author 卓大") + @GetMapping("/role/delete/{roleId}") + @SaCheckPermission("system:role:delete") + public ResponseDTO deleteRole(@PathVariable Long roleId) { + return roleService.deleteRole(roleId); + } + + @Operation(summary = "更新角色 @author 卓大") + @PostMapping("/role/update") + @SaCheckPermission("system:role:update") + public ResponseDTO updateRole(@Valid @RequestBody RoleUpdateForm roleUpdateDTO) { + return roleService.updateRole(roleUpdateDTO); + } + + @Operation(summary = "获取角色数据 @author 卓大") + @GetMapping("/role/get/{roleId}") + public ResponseDTO getRole(@PathVariable("roleId") Long roleId) { + return roleService.getRoleById(roleId); + } + + @Operation(summary = "获取所有角色 @author 卓大") + @GetMapping("/role/getAll") + public ResponseDTO> getAllRole() { + return roleService.getAllRole(); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleDataScopeController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleDataScopeController.java new file mode 100644 index 0000000..7deead5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleDataScopeController.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.system.role.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleDataScopeUpdateForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleDataScopeVO; +import net.lab1024.sa.admin.module.system.role.service.RoleDataScopeService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 角色的数据权限配置 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-02-26 22:09:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_ROLE_DATA_SCOPE) +public class RoleDataScopeController { + + @Resource + private RoleDataScopeService roleDataScopeService; + + @Operation(summary = "获取某角色所设置的数据范围 @author 卓大") + @GetMapping("/role/dataScope/getRoleDataScopeList/{roleId}") + public ResponseDTO> dataScopeListByRole(@PathVariable Long roleId) { + return roleDataScopeService.getRoleDataScopeList(roleId); + } + + @Operation(summary = "批量设置某角色数据范围 @author 卓大") + @PostMapping("/role/dataScope/updateRoleDataScopeList") + @SaCheckPermission("system:role:dataScope:update") + public ResponseDTO updateRoleDataScopeList(@RequestBody @Valid RoleDataScopeUpdateForm roleDataScopeUpdateForm) { + return roleDataScopeService.updateRoleDataScopeList(roleDataScopeUpdateForm); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleEmployeeController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleEmployeeController.java new file mode 100644 index 0000000..46676f5 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleEmployeeController.java @@ -0,0 +1,74 @@ +package net.lab1024.sa.admin.module.system.role.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleEmployeeQueryForm; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleEmployeeUpdateForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleSelectedVO; +import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 角色的员工 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-02-26 22:09:59 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_ROLE_EMPLOYEE) +public class RoleEmployeeController { + + @Resource + private RoleEmployeeService roleEmployeeService; + + @Operation(summary = "查询某个角色下的员工列表 @author 卓大") + @PostMapping("/role/employee/queryEmployee") + public ResponseDTO> queryEmployee(@Valid @RequestBody RoleEmployeeQueryForm roleEmployeeQueryForm) { + return roleEmployeeService.queryEmployee(roleEmployeeQueryForm); + } + + @Operation(summary = "获取某个角色下的所有员工列表(无分页) @author 卓大") + @GetMapping("/role/employee/getAllEmployeeByRoleId/{roleId}") + public ResponseDTO> listAllEmployeeRoleId(@PathVariable Long roleId) { + return ResponseDTO.ok(roleEmployeeService.getAllEmployeeByRoleId(roleId)); + } + + @Operation(summary = "从角色成员列表中移除员工 @author 卓大") + @GetMapping("/role/employee/removeEmployee") + @SaCheckPermission("system:role:employee:delete") + public ResponseDTO removeEmployee(Long employeeId, Long roleId) { + return roleEmployeeService.removeRoleEmployee(employeeId, roleId); + } + + @Operation(summary = "从角色成员列表中批量移除员工 @author 卓大") + @PostMapping("/role/employee/batchRemoveRoleEmployee") + @SaCheckPermission("system:role:employee:batch:delete") + public ResponseDTO batchRemoveEmployee(@Valid @RequestBody RoleEmployeeUpdateForm updateForm) { + return roleEmployeeService.batchRemoveRoleEmployee(updateForm); + } + + @Operation(summary = "角色成员列表中批量添加员工 @author 卓大") + @PostMapping("/role/employee/batchAddRoleEmployee") + @SaCheckPermission("system:role:employee:add") + public ResponseDTO addEmployeeList(@Valid @RequestBody RoleEmployeeUpdateForm addForm) { + return roleEmployeeService.batchAddRoleEmployee(addForm); + } + + @Operation(summary = "获取员工所有选中的角色和所有角色 @author 卓大") + @GetMapping("/role/employee/getRoles/{employeeId}") + public ResponseDTO> getRoleByEmployeeId(@PathVariable Long employeeId) { + return ResponseDTO.ok(roleEmployeeService.getRoleInfoListByEmployeeId(employeeId)); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleMenuController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleMenuController.java new file mode 100644 index 0000000..510ccc8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/controller/RoleMenuController.java @@ -0,0 +1,43 @@ +package net.lab1024.sa.admin.module.system.role.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleMenuUpdateForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleMenuTreeVO; +import net.lab1024.sa.admin.module.system.role.service.RoleMenuService; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import org.springframework.web.bind.annotation.*; + +/** + * 角色的菜单 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-02-26 21:34:01 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_ROLE_MENU) +public class RoleMenuController { + + @Resource + private RoleMenuService roleMenuService; + + @Operation(summary = "更新角色权限 @author 卓大") + @PostMapping("/role/menu/updateRoleMenu") + @SaCheckPermission("system:role:menu:update") + public ResponseDTO updateRoleMenu(@Valid @RequestBody RoleMenuUpdateForm updateDTO) { + return roleMenuService.updateRoleMenu(updateDTO); + } + + @Operation(summary = "获取角色关联菜单权限 @author 卓大") + @GetMapping("/role/menu/getRoleSelectedMenu/{roleId}") + public ResponseDTO getRoleSelectedMenu(@PathVariable Long roleId) { + return roleMenuService.getRoleSelectedMenu(roleId); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleDao.java new file mode 100644 index 0000000..9cb9b1e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleDao.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.admin.module.system.role.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEntity; + +/** + * 角色 dao + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-02-26 21:34:01 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface RoleDao extends BaseMapper { + + /** + * 根据角色名称查询 + */ + RoleEntity getByRoleName(@Param("roleName") String roleName); + + /** + * 根据角色编码 + */ + RoleEntity getByRoleCode(@Param("roleCode") String roleCode); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleDataScopeDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleDataScopeDao.java new file mode 100644 index 0000000..16ddf39 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleDataScopeDao.java @@ -0,0 +1,39 @@ +package net.lab1024.sa.admin.module.system.role.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleDataScopeEntity; + +import java.util.List; + + +/** + * 角色 数据权限 dao + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-02-26 21:34:01 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface RoleDataScopeDao extends BaseMapper { + + /** + * 获取某个角色的设置信息 + */ + List listByRoleId(@Param("roleId") Long roleId); + + /** + * 获取某批角色的所有数据范围配置信息 + */ + List listByRoleIdList(@Param("roleIdList") List roleIdList); + + /** + * 删除某个角色的设置信息 + */ + void deleteByRoleId(@Param("roleId") Long roleId); + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleEmployeeDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleEmployeeDao.java new file mode 100644 index 0000000..71de64c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleEmployeeDao.java @@ -0,0 +1,88 @@ +package net.lab1024.sa.admin.module.system.role.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; +import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEmployeeEntity; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleEmployeeQueryForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleEmployeeVO; + +import java.util.List; +import java.util.Set; + + +/** + * 角色 员工 dao + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-03-07 18:54:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface RoleEmployeeDao extends BaseMapper { + + /** + * 根据员工id 查询所有的角色 + */ + List selectRoleByEmployeeId(@Param("employeeId") Long employeeId); + + /** + * 根据员工id 查询所有的角色io集合 + */ + List selectRoleIdByEmployeeId(@Param("employeeId") Long employeeId); + + /** + * 根据员工id 查询所有的角色 + */ + List selectRoleIdByEmployeeIdList(@Param("employeeIdList") List employeeIdList); + + /** + * 根据员工id 查询所有的角色 + */ + List selectRoleByEmployeeIdList(@Param("employeeIdList") List employeeIdList); + + /** + * 查询角色下的人员id + */ + Set selectEmployeeIdByRoleIdList(@Param("roleIdList") List roleIdList); + + /** + * + */ + List selectRoleEmployeeByName(Page page, @Param("queryForm") RoleEmployeeQueryForm roleEmployeeQueryForm); + + /** + * + */ + List selectEmployeeByRoleId(@Param("roleId") Long roleId); + /** + * 根据员工信息删除 + */ + void deleteByEmployeeId(@Param("employeeId") Long employeeId); + + /** + * 删除某个角色的所有关系 + */ + void deleteByRoleId(@Param("roleId")Long roleId); + + /** + * 根据员工和 角色删除关系 + */ + void deleteByEmployeeIdRoleId(@Param("employeeId") Long employeeId,@Param("roleId")Long roleId); + + /** + * 批量删除某个角色下的某批用户的关联关系 + */ + void batchDeleteEmployeeRole(@Param("roleId") Long roleId, @Param("employeeIds") Set employeeIds); + + /** + * 判断某个角色下是否存在用户 + */ + Integer existsByRoleId(@Param("roleId") Long roleId); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleMenuDao.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleMenuDao.java new file mode 100644 index 0000000..dd11d84 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/dao/RoleMenuDao.java @@ -0,0 +1,47 @@ +package net.lab1024.sa.admin.module.system.role.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import net.lab1024.sa.admin.module.system.menu.domain.entity.MenuEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleMenuEntity; + +import java.util.List; + +/** + * 角色 菜单 dao + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-07 18:54:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Mapper +public interface RoleMenuDao extends BaseMapper { + + /** + * 根据角色ID删除菜单权限 + * + */ + void deleteByRoleId(@Param("roleId") Long roleId); + + /** + * 根据角色ID查询选择的菜单权限 + * + */ + List queryMenuIdByRoleId(@Param("roleId") Long roleId); + + /** + * 根据角色ID集合查询选择的菜单权限 + * + */ + List selectMenuListByRoleIdList(@Param("roleIdList") List roleIdList, @Param("deletedFlag") Boolean deletedFlag); + + /** + * 查询所有的菜单角色 + * + */ + List queryAllRoleMenu(); +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleDataScopeEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleDataScopeEntity.java new file mode 100644 index 0000000..74c8b58 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleDataScopeEntity.java @@ -0,0 +1,53 @@ +package net.lab1024.sa.admin.module.system.role.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeTypeEnum; +import net.lab1024.sa.admin.module.system.datascope.constant.DataScopeViewTypeEnum; + +import java.time.LocalDateTime; + +/** + * 数据范围与角色关系 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-03-07 18:54:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_role_data_scope") +public class RoleDataScopeEntity { + /** + * 主键id + */ + @TableId(type = IdType.AUTO) + private Long id; + /** + * 数据范围id + * {@link DataScopeTypeEnum} + */ + private Integer dataScopeType; + /** + * 数据范围类型 + * {@link DataScopeViewTypeEnum} + */ + private Integer viewType; + /** + * 角色id + */ + private Long roleId; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建时间 + */ + private LocalDateTime createTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleEmployeeEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleEmployeeEntity.java new file mode 100644 index 0000000..6fee68d --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleEmployeeEntity.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.admin.module.system.role.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 角色 员工关系 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-03-07 18:54:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_role_employee") +public class RoleEmployeeEntity { + + @TableId(type = IdType.AUTO) + private Long id; + + private Long roleId; + + private Long employeeId; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; + + public RoleEmployeeEntity() { + } + + public RoleEmployeeEntity(Long roleId, Long employeeId) { + this.roleId = roleId; + this.employeeId = employeeId; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleEntity.java new file mode 100644 index 0000000..27703df --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleEntity.java @@ -0,0 +1,52 @@ +package net.lab1024.sa.admin.module.system.role.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 角色 + * + * @Author 1024创新实验室: 胡克 + * @Date 2022-03-07 18:54:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_role") +public class RoleEntity { + /** + * 主键id + */ + @TableId(type = IdType.AUTO) + private Long roleId; + + /** + * 角色名称 + */ + private String roleName; + + /** + * 角色编码 + */ + private String roleCode; + + /** + * 角色备注 + */ + private String remark; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建时间 + */ + private LocalDateTime createTime; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleMenuEntity.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleMenuEntity.java new file mode 100644 index 0000000..424a742 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/entity/RoleMenuEntity.java @@ -0,0 +1,49 @@ +package net.lab1024.sa.admin.module.system.role.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 角色 菜单 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-03-16 23:00:57 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +@TableName("t_smart_role_menu") +public class RoleMenuEntity { + + /** + * 主键id + */ + @TableId(type = IdType.AUTO) + private Long roleMenuId; + + /** + * 角色 id + */ + private Long roleId; + + /** + * 菜单 id + */ + private Long menuId; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleAddForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleAddForm.java new file mode 100644 index 0000000..cc06bdc --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleAddForm.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.admin.module.system.role.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +/** + * 角色 添加表单 + * + * @Author 1024创新实验室: 胡克 + * @Date 2022-02-26 19:09:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleAddForm { + + /** + * 角色名称 + */ + @Schema(description = "角色名称") + @NotNull(message = "角色名称不能为空") + @Length(min = 1, max = 20, message = "角色名称(1-20)个字符") + private String roleName; + + @Schema(description = "角色编码") + @NotNull(message = "角色编码 不能为空") + @Length(min = 1, max = 20, message = "角色编码(1-20)个字符") + private String roleCode; + + /** + * 角色描述 + */ + @Schema(description = "角色描述") + @Length(max = 255, message = "角色描述最多255个字符") + private String remark; + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleDataScopeUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleDataScopeUpdateForm.java new file mode 100644 index 0000000..7a48fa0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleDataScopeUpdateForm.java @@ -0,0 +1,43 @@ +package net.lab1024.sa.admin.module.system.role.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +/** + * 角色的数据范围更新 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleDataScopeUpdateForm { + + @Schema(description = "角色id") + @NotNull(message = "角色id不能为空") + private Long roleId; + + @Schema(description = "设置信息") + @Valid + private List dataScopeItemList; + + + @Data + public static class RoleUpdateDataScopeListFormItem { + + @Schema(description = "数据范围类型") + @NotNull(message = "数据范围类型不能为空") + private Integer dataScopeType; + + @Schema(description = "可见范围") + @NotNull(message = "可见范围不能为空") + private Integer viewType; + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleEmployeeQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleEmployeeQueryForm.java new file mode 100644 index 0000000..46b21e8 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleEmployeeQueryForm.java @@ -0,0 +1,24 @@ +package net.lab1024.sa.admin.module.system.role.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; + +/** + * 角色的员工查询 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleEmployeeQueryForm extends PageParam { + + @Schema(description = "关键字") + private String keywords; + + @Schema(description = "角色id") + private String roleId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleEmployeeUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleEmployeeUpdateForm.java new file mode 100644 index 0000000..d4d2dc4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleEmployeeUpdateForm.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.admin.module.system.role.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.Set; + +/** + * 角色的员工更新 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleEmployeeUpdateForm { + + @Schema(description = "角色id") + @NotNull(message = "角色id不能为空") + protected Long roleId; + + @Schema(description = "员工id集合") + @NotEmpty(message = "员工id不能为空") + protected Set employeeIdList; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleMenuUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleMenuUpdateForm.java new file mode 100644 index 0000000..ec58963 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleMenuUpdateForm.java @@ -0,0 +1,35 @@ +package net.lab1024.sa.admin.module.system.role.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +/** + * 角色的菜单更新 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleMenuUpdateForm { + + /** + * 角色id + */ + @Schema(description = "角色id") + @NotNull(message = "角色id不能为空") + private Long roleId; + + /** + * 菜单ID 集合 + */ + @Schema(description = "菜单ID集合") + @NotNull(message = "菜单ID不能为空") + private List menuIdList; + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleQueryForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleQueryForm.java new file mode 100644 index 0000000..cf754e4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleQueryForm.java @@ -0,0 +1,24 @@ +package net.lab1024.sa.admin.module.system.role.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; + +/** + * 角色 查询 + * + * @Author 1024创新实验室: 胡克 + * @Date 2022-02-26 19:09:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleQueryForm extends PageParam { + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "角色id") + private String roleId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleUpdateForm.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleUpdateForm.java new file mode 100644 index 0000000..19a42f1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/form/RoleUpdateForm.java @@ -0,0 +1,27 @@ +package net.lab1024.sa.admin.module.system.role.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 角色更新修改 + * + * @Author 1024创新实验室: 胡克 + * @Date 2022-02-26 19:09:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleUpdateForm extends RoleAddForm { + + /** + * 角色id + */ + @Schema(description = "角色id") + @NotNull(message = "角色id不能为空") + protected Long roleId; + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleDataScopeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleDataScopeVO.java new file mode 100644 index 0000000..350b644 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleDataScopeVO.java @@ -0,0 +1,23 @@ +package net.lab1024.sa.admin.module.system.role.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 角色的数据范围 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleDataScopeVO { + + @Schema(description = "数据范围id") + private Integer dataScopeType; + + @Schema(description = "可见范围") + private Integer viewType; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleEmployeeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleEmployeeVO.java new file mode 100644 index 0000000..83d4023 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleEmployeeVO.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.admin.module.system.role.domain.vo; + +import lombok.Data; + +/** + * 角色的员工 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleEmployeeVO { + + private Long roleId; + + private Long employeeId; + + private String roleName; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleMenuTreeVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleMenuTreeVO.java new file mode 100644 index 0000000..2809115 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleMenuTreeVO.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.admin.module.system.role.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuSimpleTreeVO; + +import java.util.List; + +/** + * 角色菜单树 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleMenuTreeVO { + + @Schema(description = "角色ID") + private Long roleId; + + @Schema(description = "菜单列表") + private List menuTreeList; + + @Schema(description = "选中的菜单ID") + private List selectedMenuId; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleSelectedVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleSelectedVO.java new file mode 100644 index 0000000..1165cff --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleSelectedVO.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.system.role.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 选择角色 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleSelectedVO extends RoleVO { + + @Schema(description = "角色名称") + private Boolean selected; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleVO.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleVO.java new file mode 100644 index 0000000..767cda9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/domain/vo/RoleVO.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.admin.module.system.role.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 角色 + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class RoleVO { + + @Schema(description = "角色ID") + private Long roleId; + + @Schema(description = "角色名称") + private String roleName; + + @Schema(description = "角色编码") + private String roleCode; + + @Schema(description = "角色备注") + private String remark; +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleDataScopeManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleDataScopeManager.java new file mode 100644 index 0000000..bc9e0a4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleDataScopeManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.system.role.manager; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.lab1024.sa.admin.module.system.role.dao.RoleDataScopeDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleDataScopeEntity; +import org.springframework.stereotype.Service; + +/** + * 角色 数据范围 manager + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class RoleDataScopeManager extends ServiceImpl { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleEmployeeManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleEmployeeManager.java new file mode 100644 index 0000000..ba33dfd --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleEmployeeManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.system.role.manager; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEmployeeEntity; +import org.springframework.stereotype.Service; + +/** + * 角色员工 manager + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-04-08 21:53:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class RoleEmployeeManager extends ServiceImpl { + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleMenuManager.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleMenuManager.java new file mode 100644 index 0000000..f114531 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleMenuManager.java @@ -0,0 +1,38 @@ +package net.lab1024.sa.admin.module.system.role.manager; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.role.dao.RoleMenuDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleMenuEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 角色-菜单 manager + * + * @Author 1024创新实验室: 善逸 + * @Date 2022-04-09 19:05:49 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class RoleMenuManager extends ServiceImpl { + + @Resource + private RoleMenuDao roleMenuDao; + + /** + * 更新角色权限 + * + */ + @Transactional(rollbackFor = Exception.class) + public void updateRoleMenu(Long roleId, List roleMenuEntityList) { + // 根据角色ID删除菜单权限 + roleMenuDao.deleteByRoleId(roleId); + // 批量添加菜单权限 + saveBatch(roleMenuEntityList); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleDataScopeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleDataScopeService.java new file mode 100644 index 0000000..40211bf --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleDataScopeService.java @@ -0,0 +1,63 @@ +package net.lab1024.sa.admin.module.system.role.service; + +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleDataScopeEntity; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleDataScopeUpdateForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleDataScopeVO; +import net.lab1024.sa.admin.module.system.role.manager.RoleDataScopeManager; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.List; + +/** + * 角色-数据范围 + * + * @Author 1024创新实验室: 善逸 + * @Date 2021-10-22 23:17:47 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class RoleDataScopeService { + + @Resource + private RoleDataScopeManager roleDataScopeManager; + + + /** + * 获取某个角色的数据范围设置信息 + * + */ + public ResponseDTO> getRoleDataScopeList(Long roleId) { + List roleDataScopeEntityList = roleDataScopeManager.getBaseMapper().listByRoleId(roleId); + if (CollectionUtils.isEmpty(roleDataScopeEntityList)) { + return ResponseDTO.ok(Lists.newArrayList()); + } + List roleDataScopeList = SmartBeanUtil.copyList(roleDataScopeEntityList, RoleDataScopeVO.class); + return ResponseDTO.ok(roleDataScopeList); + } + + /** + * 批量设置某个角色的数据范围设置信息 + * + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO updateRoleDataScopeList(RoleDataScopeUpdateForm roleDataScopeUpdateForm) { + List batchSetList = roleDataScopeUpdateForm.getDataScopeItemList(); + if (CollectionUtils.isEmpty(batchSetList)) { + return ResponseDTO.error(UserErrorCode.PARAM_ERROR, "缺少配置信息"); + } + List roleDataScopeEntityList = SmartBeanUtil.copyList(batchSetList, RoleDataScopeEntity.class); + roleDataScopeEntityList.forEach(e -> e.setRoleId(roleDataScopeUpdateForm.getRoleId())); + roleDataScopeManager.getBaseMapper().deleteByRoleId(roleDataScopeUpdateForm.getRoleId()); + roleDataScopeManager.saveBatch(roleDataScopeEntityList); + return ResponseDTO.ok(); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleEmployeeService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleEmployeeService.java new file mode 100644 index 0000000..88e22dc --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleEmployeeService.java @@ -0,0 +1,154 @@ +package net.lab1024.sa.admin.module.system.role.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.department.dao.DepartmentDao; +import net.lab1024.sa.admin.module.system.department.domain.entity.DepartmentEntity; +import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO; +import net.lab1024.sa.admin.module.system.role.dao.RoleDao; +import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEmployeeEntity; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEntity; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleEmployeeQueryForm; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleEmployeeUpdateForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleSelectedVO; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO; +import net.lab1024.sa.admin.module.system.role.manager.RoleEmployeeManager; +import net.lab1024.sa.base.common.constant.StringConst; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 角色-员工 + * + * @Author 1024创新实验室: 善逸 + * @Date 2021-10-22 23:17:47 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class RoleEmployeeService { + + @Resource + private RoleEmployeeDao roleEmployeeDao; + @Resource + private RoleDao roleDao; + @Resource + private DepartmentDao departmentDao; + @Resource + private RoleEmployeeManager roleEmployeeManager; + + + /** + * 批量插入 + * + */ + public void batchInsert(List roleEmployeeList) { + roleEmployeeManager.saveBatch(roleEmployeeList); + } + + /** + * 通过角色id,分页获取成员员工列表 + * + */ + public ResponseDTO> queryEmployee(RoleEmployeeQueryForm roleEmployeeQueryForm) { + Page page = SmartPageUtil.convert2PageQuery(roleEmployeeQueryForm); + List employeeList = roleEmployeeDao.selectRoleEmployeeByName(page, roleEmployeeQueryForm) + .stream() + .filter(Objects::nonNull) + .collect(Collectors.toList()); + List departmentIdList = employeeList.stream().filter(e -> e != null && e.getDepartmentId() != null).map(EmployeeVO::getDepartmentId).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(departmentIdList)) { + List departmentEntities = departmentDao.selectBatchIds(departmentIdList); + Map departmentIdNameMap = departmentEntities.stream().collect(Collectors.toMap(DepartmentEntity::getDepartmentId, DepartmentEntity::getDepartmentName)); + employeeList.forEach(e -> { + e.setDepartmentName(departmentIdNameMap.getOrDefault(e.getDepartmentId(), StringConst.EMPTY)); + }); + } + PageResult pageResult = SmartPageUtil.convert2PageResult(page, employeeList, EmployeeVO.class); + return ResponseDTO.ok(pageResult); + } + + public List getAllEmployeeByRoleId(Long roleId) { + return roleEmployeeDao.selectEmployeeByRoleId(roleId); + } + + /** + * 移除员工角色 + * + */ + public ResponseDTO removeRoleEmployee(Long employeeId, Long roleId) { + if (null == employeeId || null == roleId) { + return ResponseDTO.userErrorParam(); + } + roleEmployeeDao.deleteByEmployeeIdRoleId(employeeId, roleId); + return ResponseDTO.ok(); + } + + /** + * 批量删除角色的成员员工 + * + */ + public ResponseDTO batchRemoveRoleEmployee(RoleEmployeeUpdateForm roleEmployeeUpdateForm) { + roleEmployeeDao.batchDeleteEmployeeRole(roleEmployeeUpdateForm.getRoleId(), roleEmployeeUpdateForm.getEmployeeIdList()); + return ResponseDTO.ok(); + } + + /** + * 批量添加角色的成员员工 + * + */ + public ResponseDTO batchAddRoleEmployee(RoleEmployeeUpdateForm roleEmployeeUpdateForm) { + Long roleId = roleEmployeeUpdateForm.getRoleId(); + + // 已选择的员工id列表 + Set selectedEmployeeIdList = roleEmployeeUpdateForm.getEmployeeIdList(); + // 数据库里已有的员工id列表 + Set dbEmployeeIdList = roleEmployeeDao.selectEmployeeIdByRoleIdList(Lists.newArrayList(roleId)); + // 从已选择的员工id列表里 过滤数据库里不存在的 即需要添加的员工 id + Set addEmployeeIdList = selectedEmployeeIdList.stream().filter(id -> !dbEmployeeIdList.contains(id)).collect(Collectors.toSet()); + + // 添加角色员工 + if (CollectionUtils.isNotEmpty(addEmployeeIdList)) { + List roleEmployeeList = addEmployeeIdList.stream() + .map(employeeId -> new RoleEmployeeEntity(roleId, employeeId)) + .collect(Collectors.toList()); + roleEmployeeManager.saveBatch(roleEmployeeList); + } + return ResponseDTO.ok(); + } + + /** + * 通过员工id获取员工角色 + * + */ + public List getRoleInfoListByEmployeeId(Long employeeId) { + List roleIds = roleEmployeeDao.selectRoleIdByEmployeeId(employeeId); + List roleList = roleDao.selectList(null); + List result = SmartBeanUtil.copyList(roleList, RoleSelectedVO.class); + result.stream().forEach(item -> item.setSelected(roleIds.contains(item.getRoleId()))); + return result; + } + + /** + * 根据员工id 查询角色id集合 + * + */ + public List getRoleIdList(Long employeeId) { + return roleEmployeeDao.selectRoleByEmployeeId(employeeId); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleMenuService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleMenuService.java new file mode 100644 index 0000000..3b4ecad --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleMenuService.java @@ -0,0 +1,123 @@ +package net.lab1024.sa.admin.module.system.role.service; + +import com.google.common.collect.Lists; +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.menu.dao.MenuDao; +import net.lab1024.sa.admin.module.system.menu.domain.entity.MenuEntity; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuSimpleTreeVO; +import net.lab1024.sa.admin.module.system.menu.domain.vo.MenuVO; +import net.lab1024.sa.admin.module.system.role.dao.RoleDao; +import net.lab1024.sa.admin.module.system.role.dao.RoleMenuDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEntity; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleMenuEntity; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleMenuUpdateForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleMenuTreeVO; +import net.lab1024.sa.admin.module.system.role.manager.RoleMenuManager; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 角色-菜单 + * + * @Author 1024创新实验室: 善逸 + * @Date 2021-10-22 23:17:47 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class RoleMenuService { + + @Resource + private RoleDao roleDao; + @Resource + private RoleMenuDao roleMenuDao; + @Resource + private RoleMenuManager roleMenuManager; + @Resource + private MenuDao menuDao; + + /** + * 更新角色权限 + * + */ + public ResponseDTO updateRoleMenu(RoleMenuUpdateForm roleMenuUpdateForm) { + //查询角色是否存在 + Long roleId = roleMenuUpdateForm.getRoleId(); + RoleEntity roleEntity = roleDao.selectById(roleId); + if (null == roleEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + List roleMenuEntityList = Lists.newArrayList(); + RoleMenuEntity roleMenuEntity; + for (Long menuId : roleMenuUpdateForm.getMenuIdList()) { + roleMenuEntity = new RoleMenuEntity(); + roleMenuEntity.setRoleId(roleId); + roleMenuEntity.setMenuId(menuId); + roleMenuEntityList.add(roleMenuEntity); + } + roleMenuManager.updateRoleMenu(roleMenuUpdateForm.getRoleId(), roleMenuEntityList); + return ResponseDTO.ok(); + } + + /** + * 根据角色id集合,查询其所有的菜单权限 + * + */ + public List getMenuList(List roleIdList, Boolean administratorFlag) { + //管理员返回所有菜单 + if(administratorFlag){ + List menuEntityList = roleMenuDao.selectMenuListByRoleIdList(Lists.newArrayList(), false); + return SmartBeanUtil.copyList(menuEntityList, MenuVO.class); + } + //非管理员 无角色 返回空菜单 + if (CollectionUtils.isEmpty(roleIdList)) { + return new ArrayList<>(); + } + List menuEntityList = roleMenuDao.selectMenuListByRoleIdList(roleIdList, false); + return SmartBeanUtil.copyList(menuEntityList, MenuVO.class); + } + + + /** + * 获取角色关联菜单权限 + * + */ + public ResponseDTO getRoleSelectedMenu(Long roleId) { + RoleMenuTreeVO res = new RoleMenuTreeVO(); + res.setRoleId(roleId); + //查询角色ID选择的菜单权限 + List selectedMenuId = roleMenuDao.queryMenuIdByRoleId(roleId); + res.setSelectedMenuId(selectedMenuId); + //查询菜单权限 + List menuVOList = menuDao.queryMenuList(Boolean.FALSE, Boolean.FALSE, null); + Map> parentMap = menuVOList.stream().collect(Collectors.groupingBy(MenuVO::getParentId, Collectors.toList())); + List menuTreeList = this.buildMenuTree(parentMap, NumberUtils.LONG_ZERO); + res.setMenuTreeList(menuTreeList); + return ResponseDTO.ok(res); + } + + /** + * 构建菜单树 + * + */ + private List buildMenuTree(Map> parentMap, Long parentId) { + // 获取本级菜单树List + List res = parentMap.getOrDefault(parentId, Lists.newArrayList()).stream() + .map(e -> SmartBeanUtil.copy(e, MenuSimpleTreeVO.class)).collect(Collectors.toList()); + // 循环遍历下级菜单 + res.forEach(e -> { + e.setChildren(this.buildMenuTree(parentMap, e.getMenuId())); + }); + return res; + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleService.java new file mode 100644 index 0000000..56fbd34 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/service/RoleService.java @@ -0,0 +1,123 @@ +package net.lab1024.sa.admin.module.system.role.service; + +import jakarta.annotation.Resource; +import net.lab1024.sa.admin.module.system.role.dao.RoleDao; +import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao; +import net.lab1024.sa.admin.module.system.role.dao.RoleMenuDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEntity; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleAddForm; +import net.lab1024.sa.admin.module.system.role.domain.form.RoleUpdateForm; +import net.lab1024.sa.admin.module.system.role.domain.vo.RoleVO; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 角色 + * + * @Author 1024创新实验室: 胡克 + * @Date 2021-08-16 20:19:22 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Service +public class RoleService { + + @Resource + private RoleDao roleDao; + + @Resource + private RoleMenuDao roleMenuDao; + + @Resource + private RoleEmployeeDao roleEmployeeDao; + + /** + * 新增添加角色 + */ + public ResponseDTO addRole(RoleAddForm roleAddForm) { + RoleEntity existRoleEntity = roleDao.getByRoleName(roleAddForm.getRoleName()); + if (null != existRoleEntity) { + return ResponseDTO.userErrorParam("角色名称重复"); + } + + existRoleEntity = roleDao.getByRoleCode(roleAddForm.getRoleCode()); + if (null != existRoleEntity) { + return ResponseDTO.userErrorParam("角色编码重复,重复的角色为:" + existRoleEntity.getRoleName()); + } + + RoleEntity roleEntity = SmartBeanUtil.copy(roleAddForm, RoleEntity.class); + roleDao.insert(roleEntity); + return ResponseDTO.ok(); + } + + /** + * 根据角色id 删除 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO deleteRole(Long roleId) { + RoleEntity roleEntity = roleDao.selectById(roleId); + if (null == roleEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + // 当没有员工绑定这个角色时才可以删除 + Integer exists = roleEmployeeDao.existsByRoleId(roleId); + if (exists != null) { + return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, "该角色下存在员工,无法删除"); + } + roleDao.deleteById(roleId); + roleMenuDao.deleteByRoleId(roleId); + roleEmployeeDao.deleteByRoleId(roleId); + return ResponseDTO.ok(); + } + + /** + * 更新角色 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO updateRole(RoleUpdateForm roleUpdateForm) { + if (null == roleDao.selectById(roleUpdateForm.getRoleId())) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + + RoleEntity existRoleEntity = roleDao.getByRoleName(roleUpdateForm.getRoleName()); + if (null != existRoleEntity && !existRoleEntity.getRoleId().equals(roleUpdateForm.getRoleId())) { + return ResponseDTO.userErrorParam("角色名称重复"); + } + + existRoleEntity = roleDao.getByRoleCode(roleUpdateForm.getRoleCode()); + if (null != existRoleEntity && !existRoleEntity.getRoleId().equals(roleUpdateForm.getRoleId())) { + return ResponseDTO.userErrorParam("角色编码重复,重复的角色为:" + existRoleEntity.getRoleName()); + } + + RoleEntity roleEntity = SmartBeanUtil.copy(roleUpdateForm, RoleEntity.class); + roleDao.updateById(roleEntity); + return ResponseDTO.ok(); + } + + /** + * 根据id获取角色数据 + */ + public ResponseDTO getRoleById(Long roleId) { + RoleEntity roleEntity = roleDao.selectById(roleId); + if (null == roleEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + RoleVO role = SmartBeanUtil.copy(roleEntity, RoleVO.class); + return ResponseDTO.ok(role); + } + + /** + * 获取所有角色列表 + */ + public ResponseDTO> getAllRole() { + List roleEntityList = roleDao.selectList(null); + List roleList = SmartBeanUtil.copyList(roleEntityList, RoleVO.class); + return ResponseDTO.ok(roleList); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminApiEncryptController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminApiEncryptController.java new file mode 100644 index 0000000..4bd7043 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminApiEncryptController.java @@ -0,0 +1,81 @@ +package net.lab1024.sa.admin.module.system.support; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.ValidateList; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.apiencrypt.annotation.ApiDecrypt; +import net.lab1024.sa.base.module.support.apiencrypt.annotation.ApiEncrypt; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * + * api 加密 + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2023/10/21 09:21:20 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室,Since 2012 + */ + +@RestController +@Tag(name = SwaggerTagConst.Support.PROTECT) +public class AdminApiEncryptController extends SupportBaseController { + + + @ApiDecrypt + @PostMapping("/apiEncrypt/testRequestEncrypt") + @Operation(summary = "测试 请求加密") + public ResponseDTO testRequestEncrypt(@RequestBody @Valid JweForm form) { + return ResponseDTO.ok(form); + } + + @ApiEncrypt + @PostMapping("/apiEncrypt/testResponseEncrypt") + @Operation(summary = "测试 返回加密") + public ResponseDTO testResponseEncrypt(@RequestBody @Valid JweForm form) { + return ResponseDTO.ok(form); + } + + @ApiDecrypt + @ApiEncrypt + @PostMapping("/apiEncrypt/testDecryptAndEncrypt") + @Operation(summary = "测试 请求参数加密和解密、返回数据加密和解密") + public ResponseDTO testDecryptAndEncrypt(@RequestBody @Valid JweForm form) { + return ResponseDTO.ok(form); + } + + @ApiDecrypt + @ApiEncrypt + @PostMapping("/apiEncrypt/testArray") + @Operation(summary = "测试 数组加密和解密") + public ResponseDTO> testArray(@RequestBody @Valid ValidateList list) { + return ResponseDTO.ok(list); + } + + + @Data + public static class JweForm { + + @NotBlank(message = "姓名 不能为空") + String name; + + @NotNull + @Min(value = 1) + Integer age; + + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminCacheController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminCacheController.java new file mode 100644 index 0000000..adaacdb --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminCacheController.java @@ -0,0 +1,55 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.cache.CacheService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 缓存 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2021/10/11 20:07 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = SwaggerTagConst.Support.CACHE) +public class AdminCacheController extends SupportBaseController { + + @Resource + private CacheService cacheService; + + @Operation(summary = "获取所有缓存 @author 罗伊") + @GetMapping("/cache/names") + @SaCheckPermission("support:cache:keys") + public ResponseDTO> cacheNames() { + return ResponseDTO.ok(cacheService.cacheNames()); + } + + @Operation(summary = "移除某个缓存 @author 罗伊") + @GetMapping("/cache/remove/{cacheName}") + @SaCheckPermission("support:cache:delete") + public ResponseDTO removeCache(@PathVariable String cacheName) { + cacheService.removeCache(cacheName); + return ResponseDTO.ok(); + } + + @Operation(summary = "获取某个缓存的所有key @author 罗伊") + @GetMapping("/cache/keys/{cacheName}") + @SaCheckPermission("support:cache:keys") + public ResponseDTO> cacheKeys(@PathVariable String cacheName) { + return ResponseDTO.ok(cacheService.cacheKey(cacheName)); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminChangeLogController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminChangeLogController.java new file mode 100644 index 0000000..3f9faed --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminChangeLogController.java @@ -0,0 +1,59 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.ValidateList; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.changelog.domain.form.ChangeLogAddForm; +import net.lab1024.sa.base.module.support.changelog.domain.form.ChangeLogUpdateForm; +import net.lab1024.sa.base.module.support.changelog.service.ChangeLogService; +import org.springframework.web.bind.annotation.*; + +/** + * 系统更新日志 Controller + * + * @Author 卓大 + * @Date 2022-09-26 14:53:50 + * @Copyright 1024创新实验室 + */ + +@RestController +@Tag(name = SwaggerTagConst.Support.CHANGE_LOG) +public class AdminChangeLogController extends SupportBaseController { + + @Resource + private ChangeLogService changeLogService; + + @Operation(summary = "添加 @author 卓大") + @PostMapping("/changeLog/add") + @SaCheckPermission("support:changeLog:add") + public ResponseDTO add(@RequestBody @Valid ChangeLogAddForm addForm) { + return changeLogService.add(addForm); + } + + @Operation(summary = "更新 @author 卓大") + @PostMapping("/changeLog/update") + @SaCheckPermission("support:changeLog:update") + public ResponseDTO update(@RequestBody @Valid ChangeLogUpdateForm updateForm) { + return changeLogService.update(updateForm); + } + + @Operation(summary = "批量删除 @author 卓大") + @PostMapping("/changeLog/batchDelete") + @SaCheckPermission("support:changeLog:batchDelete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return changeLogService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author 卓大") + @GetMapping("/changeLog/delete/{changeLogId}") + @SaCheckPermission("support:changeLog:delete") + public ResponseDTO batchDelete(@PathVariable Long changeLogId) { + return changeLogService.delete(changeLogId); + } +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminConfigController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminConfigController.java new file mode 100644 index 0000000..fa3d5c1 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminConfigController.java @@ -0,0 +1,58 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.config.ConfigService; +import net.lab1024.sa.base.module.support.config.domain.ConfigAddForm; +import net.lab1024.sa.base.module.support.config.domain.ConfigQueryForm; +import net.lab1024.sa.base.module.support.config.domain.ConfigUpdateForm; +import net.lab1024.sa.base.module.support.config.domain.ConfigVO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 配置 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-03-14 20:46:27 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Tag(name = SwaggerTagConst.Support.CONFIG) +@RestController +public class AdminConfigController extends SupportBaseController { + + @Resource + private ConfigService configService; + + @Operation(summary = "分页查询系统配置 @author 卓大") + @PostMapping("/config/query") + @SaCheckPermission("support:config:query") + public ResponseDTO> queryConfigPage(@RequestBody @Valid ConfigQueryForm queryForm) { + return configService.queryConfigPage(queryForm); + } + + @Operation(summary = "添加配置参数 @author 卓大") + @PostMapping("/config/add") + @SaCheckPermission("support:config:add") + public ResponseDTO addConfig(@RequestBody @Valid ConfigAddForm configAddForm) { + return configService.add(configAddForm); + } + + @Operation(summary = "修改配置参数 @author 卓大") + @PostMapping("/config/update") + @SaCheckPermission("support:config:update") + public ResponseDTO updateConfig(@RequestBody @Valid ConfigUpdateForm updateForm) { + return configService.updateConfig(updateForm); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminDataMaskingDemoController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminDataMaskingDemoController.java new file mode 100644 index 0000000..7e6156b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminDataMaskingDemoController.java @@ -0,0 +1,88 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.hutool.core.util.RandomUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.Data; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.datamasking.DataMasking; +import net.lab1024.sa.base.module.support.datamasking.DataMaskingTypeEnum; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +/** + * 数据脱敏demo + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2024/08/01 22:07:27 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室,Since 2012 + */ + +@RestController +@Tag(name = SwaggerTagConst.Support.DATA_MASKING) +public class AdminDataMaskingDemoController extends SupportBaseController { + + @Operation(summary = "数据脱敏demo @author 1024创新实验室-主任-卓大") + @GetMapping("/dataMasking/demo/query") + public ResponseDTO> query() { + + List list = new ArrayList<>(); + for (int i = 0; i < RandomUtil.randomInt(10,16); i++) { + DataVO data = new DataVO(); + data.setUserId(RandomUtil.randomLong(1328479238, 83274298347982L)); + data.setPhone("1" + RandomUtil.randomNumbers(10)); + data.setIdCard("410" + RandomUtil.randomNumbers(3) + RandomUtil.randomInt(1980, 2010) + RandomUtil.randomInt(10, 12) + RandomUtil.randomInt(10, 30) + RandomUtil.randomNumbers(4)); + data.setAddress(RandomUtil.randomBoolean() ? "河南省洛阳市洛龙区一零二四大街1024号" : "河南省郑州市高新区六边形大街六边形大楼"); + data.setPassword(RandomUtil.randomString(10)); + data.setEmail(RandomUtil.randomString(RandomUtil.randomInt(6, 10)) + "@" + RandomUtil.randomString(2) + ".com"); + data.setCarLicense("豫" + RandomStringUtils.randomAlphabetic(1).toUpperCase()+" " + RandomStringUtils.randomAlphanumeric(5).toUpperCase()); + data.setBankCard("6225" + RandomStringUtils.randomNumeric(14)); + data.setOther(RandomStringUtils.randomAlphanumeric(1, 12)); + list.add(data); + } + + return ResponseDTO.ok(list); + } + + + @Data + public static class DataVO { + + @DataMasking(DataMaskingTypeEnum.USER_ID) + private Long userId; + + @DataMasking(DataMaskingTypeEnum.PHONE) + private String phone; + + @DataMasking(DataMaskingTypeEnum.ID_CARD) + private String idCard; + + @DataMasking(DataMaskingTypeEnum.ADDRESS) + private String address; + + @DataMasking(DataMaskingTypeEnum.PASSWORD) + private String password; + + @DataMasking(DataMaskingTypeEnum.EMAIL) + private String email; + + @DataMasking(DataMaskingTypeEnum.CAR_LICENSE) + private String carLicense; + + @DataMasking(DataMaskingTypeEnum.BANK_CARD) + private String bankCard; + + @DataMasking + private String other; + + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminDictController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminDictController.java new file mode 100644 index 0000000..4c4fded --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminDictController.java @@ -0,0 +1,139 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.ValidateList; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.dict.domain.form.*; +import net.lab1024.sa.base.module.support.dict.domain.vo.DictDataVO; +import net.lab1024.sa.base.module.support.dict.domain.vo.DictVO; +import net.lab1024.sa.base.module.support.dict.service.DictService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 数据字典 Controller + * + * @Author 1024创新实验室-主任-卓大 + * @Date 2025-03-25 22:25:04 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Tag(name = SwaggerTagConst.Support.DICT) +@RestController +public class AdminDictController extends SupportBaseController { + + @Resource + private DictService dictService; + + // ------------------- 获取全部数据 ------------------- + + @Operation(summary = "获取全部数据(供前端缓存使用) @author 1024创新实验室-主任-卓大") + @GetMapping("/dict/getAllDictData") + public ResponseDTO> getAll() { + return ResponseDTO.ok(dictService.getAll()); + } + + @Operation(summary = "获取所有字典code @author 1024创新实验室-主任-卓大") + @GetMapping("/dict/getAllDict") + public ResponseDTO> getAllDict() { + return ResponseDTO.ok(dictService.getAllDict()); + } + + // ------------------- 字典 ------------------- + + @Operation(summary = "分页查询 @author 1024创新实验室-主任-卓大") + @PostMapping("/dict/queryPage") + @SaCheckPermission("support:dict:query") + public ResponseDTO> queryPage(@RequestBody @Valid DictQueryForm queryForm) { + return ResponseDTO.ok(dictService.queryPage(queryForm)); + } + + @Operation(summary = "添加 @author 1024创新实验室-主任-卓大") + @PostMapping("/dict/add") + @SaCheckPermission("support:dict:add") + public ResponseDTO add(@RequestBody @Valid DictAddForm addForm) { + return dictService.add(addForm); + } + + @Operation(summary = "更新 @author 1024创新实验室-主任-卓大") + @PostMapping("/dict/update") + @SaCheckPermission("support:dict:update") + public ResponseDTO update(@RequestBody @Valid DictUpdateForm updateForm) { + return dictService.update(updateForm); + } + + @Operation(summary = "启用/禁用 @author 1024创新实验室-主任-卓大") + @GetMapping("/dict/updateDisabled/{dictId}") + @SaCheckPermission("support:dict:updateDisabled") + public ResponseDTO updateDisabled(@PathVariable Long dictId) { + return dictService.updateDisabled(dictId); + } + + @Operation(summary = "批量删除 @author 1024创新实验室-主任-卓大") + @PostMapping("/dict/batchDelete") + @SaCheckPermission("support:dict:delete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return dictService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author 1024创新实验室-主任-卓大") + @GetMapping("/dict/delete/{dictId}") + @SaCheckPermission("support:dict:delete") + public ResponseDTO delete(@PathVariable Long dictId) { + return dictService.delete(dictId); + } + + // ------------------- 字典数据 ------------------- + + @Operation(summary = "字典数据 分页查询 @author 1024创新实验室-主任-卓大") + @GetMapping("/dict/dictData/queryDictData/{dictId}") + @SaCheckPermission("support:dictData:query") + public ResponseDTO> queryDictData(@PathVariable Long dictId) { + return ResponseDTO.ok(dictService.queryDictData(dictId)); + } + + @Operation(summary = "字典数据 启用/禁用 @author 1024创新实验室-主任-卓大") + @GetMapping("/dict/dictData/updateDisabled/{dictDataId}") + @SaCheckPermission("support:dictData:updateDisabled") + public ResponseDTO updateDictDataDisabled(@PathVariable Long dictDataId) { + return dictService.updateDictDataDisabled(dictDataId); + } + + @Operation(summary = "字典数据 添加 @author 1024创新实验室-主任-卓大") + @PostMapping("/dict/dictData/add") + @SaCheckPermission("support:dictData:add") + public ResponseDTO addDictData(@RequestBody @Valid DictDataAddForm addForm) { + return dictService.addDictData(addForm); + } + + @Operation(summary = "字典数据 更新 @author 1024创新实验室-主任-卓大") + @PostMapping("/dict/dictData/update") + @SaCheckPermission("support:dictData:update") + public ResponseDTO updateDictData(@RequestBody @Valid DictDataUpdateForm updateForm) { + return dictService.updateDictData(updateForm); + } + + @Operation(summary = "字典数据 批量删除 @author 1024创新实验室-主任-卓大") + @PostMapping("/dict/dictData/batchDelete") + @SaCheckPermission("support:dictData:delete") + public ResponseDTO batchDeleteDictData(@RequestBody ValidateList idList) { + return dictService.batchDeleteDictData(idList); + } + + @Operation(summary = "字典数据 单个删除 @author 1024创新实验室-主任-卓大") + @GetMapping("/dict/dictData/delete/{dictDataId}") + @SaCheckPermission("support:dictData:delete") + public ResponseDTO deleteDictData(@PathVariable Long dictDataId) { + return dictService.deleteDictData(dictDataId); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminFileController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminFileController.java new file mode 100644 index 0000000..746b1ea --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminFileController.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.file.domain.form.FileQueryForm; +import net.lab1024.sa.base.module.support.file.domain.vo.FileVO; +import net.lab1024.sa.base.module.support.file.service.FileService; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 文件服务 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2019年10月11日 15:34:47 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = SwaggerTagConst.Support.FILE) +public class AdminFileController extends SupportBaseController { + + @Resource + private FileService fileService; + + @Operation(summary = "分页查询 @author 1024创新实验室-主任-卓大") + @PostMapping("/file/queryPage") + @SaCheckPermission("support:file:query") + public ResponseDTO> queryPage(@RequestBody @Valid FileQueryForm queryForm) { + return ResponseDTO.ok(fileService.queryPage(queryForm)); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminHeartBeatController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminHeartBeatController.java new file mode 100644 index 0000000..9578eda --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminHeartBeatController.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.system.support; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.heartbeat.HeartBeatService; +import net.lab1024.sa.base.module.support.heartbeat.domain.HeartBeatRecordQueryForm; +import net.lab1024.sa.base.module.support.heartbeat.domain.HeartBeatRecordVO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 心跳记录 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-01-09 20:57:24 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Tag(name = SwaggerTagConst.Support.HEART_BEAT) +@RestController +public class AdminHeartBeatController extends SupportBaseController { + + @Resource + private HeartBeatService heartBeatService; + + @PostMapping("/heartBeat/query") + @Operation(summary = "查询心跳记录 @author 卓大") + public ResponseDTO> query(@RequestBody @Valid HeartBeatRecordQueryForm pageParam) { + return heartBeatService.pageQuery(pageParam); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminHelpDocController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminHelpDocController.java new file mode 100644 index 0000000..75f6f1c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminHelpDocController.java @@ -0,0 +1,104 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.helpdoc.domain.form.*; +import net.lab1024.sa.base.module.support.helpdoc.domain.vo.HelpDocDetailVO; +import net.lab1024.sa.base.module.support.helpdoc.domain.vo.HelpDocVO; +import net.lab1024.sa.base.module.support.helpdoc.service.HelpDocCatalogService; +import net.lab1024.sa.base.module.support.helpdoc.service.HelpDocService; +import net.lab1024.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 帮助文档 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-08-20 23:11:42 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Tag(name = SwaggerTagConst.Support.HELP_DOC) +@RestController +public class AdminHelpDocController extends SupportBaseController { + + @Resource + private HelpDocService helpDocService; + + @Resource + private HelpDocCatalogService helpDocCatalogService; + + // --------------------- 帮助文档 【目录管理】 ------------------------- + + + @Operation(summary = "帮助文档目录-添加 @author 卓大") + @PostMapping("/helpDoc/helpDocCatalog/add") + public ResponseDTO addHelpDocCatalog(@RequestBody @Valid HelpDocCatalogAddForm helpDocCatalogAddForm) { + return helpDocCatalogService.add(helpDocCatalogAddForm); + } + + @Operation(summary = "帮助文档目录-更新 @author 卓大") + @PostMapping("/helpDoc/helpDocCatalog/update") + public ResponseDTO updateHelpDocCatalog(@RequestBody @Valid HelpDocCatalogUpdateForm helpDocCatalogUpdateForm) { + return helpDocCatalogService.update(helpDocCatalogUpdateForm); + } + + @Operation(summary = "帮助文档目录-删除 @author 卓大") + @GetMapping("/helpDoc/helpDocCatalog/delete/{helpDocCatalogId}") + public ResponseDTO deleteHelpDocCatalog(@PathVariable Long helpDocCatalogId) { + return helpDocCatalogService.delete(helpDocCatalogId); + } + + // --------------------- 帮助文档 【管理:增、删、查、改】------------------------- + + @Operation(summary = "【管理】帮助文档-分页查询 @author 卓大") + @PostMapping("/helpDoc/query") + @SaCheckPermission("support:helpDoc:query") + public ResponseDTO> query(@RequestBody @Valid HelpDocQueryForm queryForm) { + return ResponseDTO.ok(helpDocService.query(queryForm)); + } + + @Operation(summary = "【管理】帮助文档-获取详情 @author 卓大") + @GetMapping("/helpDoc/getDetail/{helpDocId}") + @SaCheckPermission("support:helpDoc:add") + public ResponseDTO getDetail(@PathVariable Long helpDocId) { + return ResponseDTO.ok(helpDocService.getDetail(helpDocId)); + } + + @Operation(summary = "【管理】帮助文档-添加 @author 卓大") + @PostMapping("/helpDoc/add") + @RepeatSubmit + public ResponseDTO add(@RequestBody @Valid HelpDocAddForm addForm) { + return helpDocService.add(addForm); + } + + @Operation(summary = "【管理】帮助文档-更新 @author 卓大") + @PostMapping("/helpDoc/update") + @RepeatSubmit + public ResponseDTO update(@RequestBody @Valid HelpDocUpdateForm updateForm) { + return helpDocService.update(updateForm); + } + + @Operation(summary = "【管理】帮助文档-删除 @author 卓大") + @GetMapping("/helpDoc/delete/{helpDocId}") + public ResponseDTO delete(@PathVariable Long helpDocId) { + return helpDocService.delete(helpDocId); + } + + @Operation(summary = "【管理】帮助文档-根据关联id查询 @author 卓大") + @GetMapping("/helpDoc/queryHelpDocByRelationId/{relationId}") + public ResponseDTO> queryHelpDocByRelationId(@PathVariable Long relationId) { + return ResponseDTO.ok(helpDocService.queryHelpDocByRelationId(relationId)); + } + +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminLoginLogController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminLoginLogController.java new file mode 100644 index 0000000..54479cc --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminLoginLogController.java @@ -0,0 +1,53 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.loginlog.LoginLogService; +import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogQueryForm; +import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogVO; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 登录日志 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022/07/22 19:46:23 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = SwaggerTagConst.Support.LOGIN_LOG) +public class AdminLoginLogController extends SupportBaseController { + + @Resource + private LoginLogService loginLogService; + + @Operation(summary = "分页查询 @author 卓大") + @PostMapping("/loginLog/page/query") + @SaCheckPermission("support:loginLog:query") + public ResponseDTO> queryByPage(@RequestBody LoginLogQueryForm queryForm) { + return loginLogService.queryByPage(queryForm); + } + + @Operation(summary = "分页查询当前登录人信息 @author 善逸") + @PostMapping("/loginLog/page/query/login") + public ResponseDTO> queryByPageLogin(@RequestBody LoginLogQueryForm queryForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + queryForm.setUserId(requestUser.getUserId()); + queryForm.setUserType(requestUser.getUserType().getValue()); + return loginLogService.queryByPage(queryForm); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminOperateLogController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminOperateLogController.java new file mode 100644 index 0000000..43ada5e --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminOperateLogController.java @@ -0,0 +1,57 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.operatelog.OperateLogService; +import net.lab1024.sa.base.module.support.operatelog.domain.OperateLogQueryForm; +import net.lab1024.sa.base.module.support.operatelog.domain.OperateLogVO; +import org.springframework.web.bind.annotation.*; + +/** + * 操作日志 + * + * @Author 1024创新实验室: 罗伊 + * @Date 2021-12-08 20:48:52 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = SwaggerTagConst.Support.OPERATE_LOG) +public class AdminOperateLogController extends SupportBaseController { + + @Resource + private OperateLogService operateLogService; + + @Operation(summary = "分页查询 @author 罗伊") + @PostMapping("/operateLog/page/query") + @SaCheckPermission("support:operateLog:query") + public ResponseDTO> queryByPage(@RequestBody OperateLogQueryForm queryForm) { + return operateLogService.queryByPage(queryForm); + } + + @Operation(summary = "详情 @author 罗伊") + @GetMapping("/operateLog/detail/{operateLogId}") + @SaCheckPermission("support:operateLog:detail") + public ResponseDTO detail(@PathVariable Long operateLogId) { + return operateLogService.detail(operateLogId); + } + + @Operation(summary = "分页查询当前登录人信息 @author 善逸") + @PostMapping("/operateLog/page/query/login") + public ResponseDTO> queryByPageLogin(@RequestBody OperateLogQueryForm queryForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + queryForm.setOperateUserId(requestUser.getUserId()); + queryForm.setOperateUserType(requestUser.getUserType().getValue()); + return operateLogService.queryByPage(queryForm); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminProtectController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminProtectController.java new file mode 100644 index 0000000..49780a3 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminProtectController.java @@ -0,0 +1,72 @@ +package net.lab1024.sa.admin.module.system.support; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.ValidateList; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.config.ConfigKeyEnum; +import net.lab1024.sa.base.module.support.config.ConfigService; +import net.lab1024.sa.base.module.support.securityprotect.domain.Level3ProtectConfigForm; +import net.lab1024.sa.base.module.support.securityprotect.domain.LoginFailQueryForm; +import net.lab1024.sa.base.module.support.securityprotect.domain.LoginFailVO; +import net.lab1024.sa.base.module.support.securityprotect.service.Level3ProtectConfigService; +import net.lab1024.sa.base.module.support.securityprotect.service.SecurityLoginService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +/** + * 网络安全 + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2023/10/17 19:07:27 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室,Since 2012 + */ + +@RestController +@Tag(name = SwaggerTagConst.Support.PROTECT) +public class AdminProtectController extends SupportBaseController { + + @Resource + private SecurityLoginService securityLoginService; + + @Resource + private Level3ProtectConfigService level3ProtectConfigService; + + @Resource + private ConfigService configService; + + + @Operation(summary = "分页查询 @author 1024创新实验室-主任-卓大") + @PostMapping("/protect/loginFail/queryPage") + public ResponseDTO> queryPage(@RequestBody @Valid LoginFailQueryForm queryForm) { + return ResponseDTO.ok(securityLoginService.queryPage(queryForm)); + } + + + @Operation(summary = "批量删除 @author 1024创新实验室-主任-卓大") + @PostMapping("/protect/loginFail/batchDelete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return securityLoginService.batchDelete(idList); + } + + @Operation(summary = "更新三级等保配置 @author 1024创新实验室-主任-卓大") + @PostMapping("/protect/level3protect/updateConfig") + public ResponseDTO updateConfig(@RequestBody @Valid Level3ProtectConfigForm configForm) { + return level3ProtectConfigService.updateLevel3Config(configForm); + } + + @Operation(summary = "查询 三级等保配置 @author 1024创新实验室-主任-卓大") + @GetMapping("/protect/level3protect/getConfig") + public ResponseDTO getConfig() { + return ResponseDTO.ok(configService.getConfigValue(ConfigKeyEnum.LEVEL3_PROTECT_CONFIG)); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminReloadController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminReloadController.java new file mode 100644 index 0000000..afe7637 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminReloadController.java @@ -0,0 +1,54 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.reload.ReloadService; +import net.lab1024.sa.base.module.support.reload.domain.ReloadForm; +import net.lab1024.sa.base.module.support.reload.domain.ReloadItemVO; +import net.lab1024.sa.base.module.support.reload.domain.ReloadResultVO; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * reload (内存热加载、钩子等) + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2015-03-02 19:11:52 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@RestController +@Tag(name = SwaggerTagConst.Support.RELOAD) +public class AdminReloadController extends SupportBaseController { + + @Resource + private ReloadService reloadService; + + @Operation(summary = "查询reload列表 @author 开云") + @GetMapping("/reload/query") + public ResponseDTO> query() { + return reloadService.query(); + } + + @Operation(summary = "获取reload result @author 开云") + @GetMapping("/reload/result/{tag}") + @SaCheckPermission("support:reload:result") + public ResponseDTO> queryReloadResult(@PathVariable("tag") String tag) { + return reloadService.queryReloadItemResult(tag); + } + + @Operation(summary = "通过tag更新标识 @author 开云") + @PostMapping("/reload/update") + @SaCheckPermission("support:reload:update") + public ResponseDTO updateByTag(@RequestBody @Valid ReloadForm reloadForm) { + return reloadService.updateByTag(reloadForm); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSerialNumberController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSerialNumberController.java new file mode 100644 index 0000000..a405d33 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSerialNumberController.java @@ -0,0 +1,74 @@ +package net.lab1024.sa.admin.module.system.support; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartEnumUtil; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.serialnumber.constant.SerialNumberIdEnum; +import net.lab1024.sa.base.module.support.serialnumber.dao.SerialNumberDao; +import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberEntity; +import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberGenerateForm; +import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberRecordEntity; +import net.lab1024.sa.base.module.support.serialnumber.domain.SerialNumberRecordQueryForm; +import net.lab1024.sa.base.module.support.serialnumber.service.SerialNumberRecordService; +import net.lab1024.sa.base.module.support.serialnumber.service.SerialNumberService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 单据序列号 + * + * @Author 1024创新实验室-主任: 卓大 + * @Date 2022-03-25 21:46:07 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Tag(name = SwaggerTagConst.Support.SERIAL_NUMBER) +@RestController +public class AdminSerialNumberController extends SupportBaseController { + + @Resource + private SerialNumberDao serialNumberDao; + + @Resource + private SerialNumberService serialNumberService; + + @Resource + private SerialNumberRecordService serialNumberRecordService; + + @Operation(summary = "生成单号 @author 卓大") + @PostMapping("/serialNumber/generate") + @SaCheckPermission("support:serialNumber:generate") + public ResponseDTO> generate(@RequestBody @Valid SerialNumberGenerateForm generateForm) { + SerialNumberIdEnum serialNumberIdEnum = SmartEnumUtil.getEnumByValue(generateForm.getSerialNumberId(), SerialNumberIdEnum.class); + if (null == serialNumberIdEnum) { + return ResponseDTO.userErrorParam("SerialNumberId,不存在" + generateForm.getSerialNumberId()); + } + return ResponseDTO.ok(serialNumberService.generate(serialNumberIdEnum, generateForm.getCount())); + } + + @Operation(summary = "获取所有单号定义 @author 卓大") + @GetMapping("/serialNumber/all") + public ResponseDTO> getAll() { + return ResponseDTO.ok(serialNumberDao.selectList(null)); + } + + @Operation(summary = "获取生成记录 @author 卓大") + @PostMapping("/serialNumber/queryRecord") + @SaCheckPermission("support:serialNumber:record") + public ResponseDTO> queryRecord(@RequestBody @Valid SerialNumberRecordQueryForm queryForm) { + return ResponseDTO.ok(serialNumberRecordService.query(queryForm)); + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSmartJobController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSmartJobController.java new file mode 100644 index 0000000..02e5cea --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSmartJobController.java @@ -0,0 +1,94 @@ +package net.lab1024.sa.admin.module.system.support; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.job.api.SmartJobService; +import net.lab1024.sa.base.module.support.job.api.domain.*; +import net.lab1024.sa.base.module.support.job.config.SmartJobAutoConfiguration; +import net.lab1024.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.web.bind.annotation.*; + +/** + * 定时任务 管理接口 + * + * @author huke + * @date 2024/6/17 20:41 + */ +@Tag(name = SwaggerTagConst.Support.JOB) +@RestController +@ConditionalOnBean(SmartJobAutoConfiguration.class) +public class AdminSmartJobController extends SupportBaseController { + + @Autowired + private SmartJobService jobService; + + @Operation(summary = "定时任务-立即执行 @huke") + @PostMapping("/job/execute") + @RepeatSubmit + public ResponseDTO execute(@RequestBody @Valid SmartJobExecuteForm executeForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + executeForm.setUpdateName(requestUser.getUserName()); + return jobService.execute(executeForm); + } + + @Operation(summary = "定时任务-查询详情 @huke") + @GetMapping("/job/{jobId}") + public ResponseDTO queryJobInfo(@PathVariable Integer jobId) { + return jobService.queryJobInfo(jobId); + } + + @Operation(summary = "定时任务-分页查询 @huke") + @PostMapping("/job/query") + public ResponseDTO> queryJob(@RequestBody @Valid SmartJobQueryForm queryForm) { + return jobService.queryJob(queryForm); + } + + @Operation(summary = "定时任务-添加任务 @huke") + @PostMapping("/job/add") + @RepeatSubmit + public ResponseDTO addJob(@RequestBody @Valid SmartJobAddForm addForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + addForm.setUpdateName(requestUser.getUserName()); + return jobService.addJob(addForm); + } + + @Operation(summary = "定时任务-更新-任务信息 @huke") + @PostMapping("/job/update") + @RepeatSubmit + public ResponseDTO updateJob(@RequestBody @Valid SmartJobUpdateForm updateForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + updateForm.setUpdateName(requestUser.getUserName()); + return jobService.updateJob(updateForm); + } + + @Operation(summary = "定时任务-更新-开启状态 @huke") + @PostMapping("/job/update/enabled") + @RepeatSubmit + public ResponseDTO updateJobEnabled(@RequestBody @Valid SmartJobEnabledUpdateForm updateForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + updateForm.setUpdateName(requestUser.getUserName()); + return jobService.updateJobEnabled(updateForm); + } + + @Operation(summary = "定时任务-删除 @zhuoda") + @GetMapping("/job/delete") + @RepeatSubmit + public ResponseDTO deleteJob(@RequestParam Integer jobId) { + return jobService.deleteJob(jobId, SmartRequestUtil.getRequestUser()); + } + + @Operation(summary = "定时任务-执行记录-分页查询 @huke") + @PostMapping("/job/log/query") + public ResponseDTO> queryJobLog(@RequestBody @Valid SmartJobLogQueryForm queryForm) { + return jobService.queryJobLog(queryForm); + } +} \ No newline at end of file diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/util/AdminRequestUtil.java b/sa-admin/src/main/java/net/lab1024/sa/admin/util/AdminRequestUtil.java new file mode 100644 index 0000000..c7e466b --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/util/AdminRequestUtil.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.admin.util; + +import net.lab1024.sa.admin.module.system.login.domain.RequestEmployee; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.util.SmartRequestUtil; + +/** + * admin 端的请求工具类 + * + * @Author 1024创新实验室-主任:卓大 + * @Date 2023/7/28 19:39:21 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室,Since 2012 + */ +public final class AdminRequestUtil { + + + public static RequestEmployee getRequestUser() { + return (RequestEmployee) SmartRequestUtil.getRequestUser(); + } + + public static Long getRequestUserId() { + RequestUser requestUser = getRequestUser(); + return null == requestUser ? null : requestUser.getUserId(); + } + + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/util/ImageUtil.java b/sa-admin/src/main/java/net/lab1024/sa/admin/util/ImageUtil.java new file mode 100644 index 0000000..689a7b4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/util/ImageUtil.java @@ -0,0 +1,24 @@ +package net.lab1024.sa.admin.util; + +import org.springframework.core.io.ClassPathResource; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ImageUtil { + public static byte[] readImageToBytes(String imagePath) throws IOException { + ClassPathResource resource = new ClassPathResource(imagePath); + try (InputStream inputStream = resource.getInputStream(); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + return outputStream.toByteArray(); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/util/RegularUtil.java b/sa-admin/src/main/java/net/lab1024/sa/admin/util/RegularUtil.java new file mode 100644 index 0000000..fbec9e4 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/util/RegularUtil.java @@ -0,0 +1,84 @@ +package net.lab1024.sa.admin.util; + +import net.lab1024.sa.admin.config.EnvConfig; +import net.lab1024.sa.admin.config.OssConfig; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 正则类 + */ +@Component +public class RegularUtil { + private static OssConfig ossConfig; + private static EnvConfig envConfig; + + public RegularUtil( + OssConfig ossConfig, + EnvConfig envConfig + ){ + RegularUtil.ossConfig = ossConfig; + RegularUtil.envConfig = envConfig; + } + + /** + * 提取 HTML 中的 OSS 图片链接(支持 jpg/png/jpeg) + * + * @param html HTML 字符串 + * @return 图片链接列表 + */ + public List extractOssImageUrls(String html) { + List imageUrls = new ArrayList<>(); + if (html == null || html.isEmpty()) { + return imageUrls; + } + + String domain = ossConfig.getCustomDomainName(); + // 转义点号,避免正则误匹配 + String escapedDomain = Pattern.quote(domain); // 更安全地处理 https:// 域名部分 + + String env = envConfig.getActive(); + String regex = escapedDomain + "/" + env + "/static/images/exchange/[a-zA-Z0-9_\\-/.]+\\.(jpg|jpeg|png)"; + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + + Matcher matcher = pattern.matcher(html); + while (matcher.find()) { + imageUrls.add(matcher.group()); + } + + return imageUrls; + } + + /** + * 提取 HTML 中的 OSS 视频链接(支持 mp4/webm/ogg) + * + * @param html HTML 字符串 + * @return 视频链接列表 + */ + public List extractOssVideosUrls(String html) { + List imageUrls = new ArrayList<>(); + if (html == null || html.isEmpty()) { + return imageUrls; + } + + String domain = ossConfig.getCustomDomainName(); + // 转义点号,避免正则误匹配 + String escapedDomain = Pattern.quote(domain); // 更安全地处理 https:// 域名部分 + + String env = envConfig.getActive(); + String regex = escapedDomain + "/" + env + "/static/video/exchange/[a-zA-Z0-9_\\-/.]+\\.(mp4|webm|ogg)"; + Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); + + Matcher matcher = pattern.matcher(html); + while (matcher.find()) { + imageUrls.add(matcher.group()); + } + + return imageUrls; + } + +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/util/Replace.java b/sa-admin/src/main/java/net/lab1024/sa/admin/util/Replace.java new file mode 100644 index 0000000..5c3c8f9 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/util/Replace.java @@ -0,0 +1,54 @@ +package net.lab1024.sa.admin.util; + +import net.lab1024.sa.admin.config.OssConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; + +@Component +@RequestMapping("/config") +public class Replace { + private static OssConfig ossConfig; + + @Autowired + public Replace(OssConfig ossConfig) { + Replace.ossConfig = ossConfig; + } + + /** + * 增加oss地址中的前缀 + * @param url 原始URL + * @return 添加了域名前缀的URL + */ + public static String addOssDomain(String url) { + if (url == null || url.isEmpty()) { + return ""; + } + + // 如果以 / 开头,则去掉前导斜杠 + if (url.startsWith("/")) { + url = url.substring(1); + } + + // 检测第一个是否为/,是的话删除 + return ossConfig.getCustomDomainName() + url; + } + + /** + * 去除OSS地址中的域名前缀 + * @param url 可能包含域名的完整URL + * @return 去除了域名后的相对路径,如果未匹配则返回原字符串 + */ + public static String removeOssDomain(String url) { + if (url == null || url.isEmpty()) { + return ""; + } + + String customDomain = ossConfig.getCustomDomainName(); + if (customDomain != null && url.startsWith(customDomain)) { + return url.substring(customDomain.length()); + } + + return url; + } +} diff --git a/sa-admin/src/main/resources/dev/application.yaml b/sa-admin/src/main/resources/dev/application.yaml new file mode 100644 index 0000000..fe7a856 --- /dev/null +++ b/sa-admin/src/main/resources/dev/application.yaml @@ -0,0 +1,22 @@ +############################################################################################################# +# # +# 为了减少重复配置,本配置文件为此sa-admin的独有配置,更多配置请查看 sa-base 项目中的 sa-base.yaml 通用配置文件。 # +# 其中此文件中配置可以覆盖 sa-base.yaml 中的通用配置,具体实现类请看类:YamlProcessor.java # +# # +############################################################################################################# + +# 项目配置: 名称、日志目录 +project: + name: sa-admin + log-directory: ./logs/smart_admin_v3/${project.name}/${spring.profiles.active} + +# 项目端口和url根路径 +server: + port: 5480 + servlet: + context-path: / + +# 环境 +spring: + profiles: + active: '@profiles.active@' \ No newline at end of file diff --git a/sa-admin/src/main/resources/dev/log4j2-spring.xml b/sa-admin/src/main/resources/dev/log4j2-spring.xml new file mode 100644 index 0000000..cab3506 --- /dev/null +++ b/sa-admin/src/main/resources/dev/log4j2-spring.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/dev/spy.properties b/sa-admin/src/main/resources/dev/spy.properties new file mode 100644 index 0000000..667e1ea --- /dev/null +++ b/sa-admin/src/main/resources/dev/spy.properties @@ -0,0 +1,18 @@ +#相关的包 +modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory +# 日志格式 +logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger +#日志输出到控制台 +appender=com.p6spy.engine.spy.appender.StdoutLogger +# 设置 p6spy driver 代理 +deregisterdrivers=true +# 取消JDBC URL前缀 +useprefix=true +# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. +excludecategories=info,debug,result,commit,resultset +# 日期格式 +dateformat=yyyy-MM-dd HH:mm:ss +# 开启慢sql +outagedetection=true +# 慢SQL记录标准(单位秒) +outagedetectioninterval=2 \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/CaseClinicalDoctor/CaseClinicalDoctorMapper.xml b/sa-admin/src/main/resources/mapper/business/CaseClinicalDoctor/CaseClinicalDoctorMapper.xml new file mode 100644 index 0000000..f59eda8 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/CaseClinicalDoctor/CaseClinicalDoctorMapper.xml @@ -0,0 +1,77 @@ + + + + + + + case_clinical_doctor.doctor_id, + case_clinical_doctor.doctor_iden, + case_clinical_doctor.doctor_name, + case_clinical_doctor.hospital_id, + case_clinical_doctor.status, + case_clinical_doctor.avatar, + case_clinical_doctor.created_at, + case_clinical_doctor.updated_at + + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/area/AreaMapper.xml b/sa-admin/src/main/resources/mapper/business/area/AreaMapper.xml new file mode 100644 index 0000000..b10fce4 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/area/AreaMapper.xml @@ -0,0 +1,35 @@ + + + + + + + area.id, + area.create_date, + area.modify_date, + area.orders, + area.full_name, + area.name, + area.tree_path, + area.parent + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/basicHospital/BasicHospitalMapper.xml b/sa-admin/src/main/resources/mapper/business/basicHospital/BasicHospitalMapper.xml new file mode 100644 index 0000000..d010cbf --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/basicHospital/BasicHospitalMapper.xml @@ -0,0 +1,58 @@ + + + + + + + basic_hospital.hospital_id, + basic_hospital.hospital_iden, + basic_hospital.hospital_name, + basic_hospital.source, + basic_hospital.hospital_level, + basic_hospital.doctor_number, + basic_hospital.province, + basic_hospital.city, + basic_hospital.county, + basic_hospital.address, + basic_hospital.created_at, + basic_hospital.updated_at + + + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseClinicalArticle/CaseClinicalArticleLabelMapper.xml b/sa-admin/src/main/resources/mapper/business/caseClinicalArticle/CaseClinicalArticleLabelMapper.xml new file mode 100644 index 0000000..cc2aea5 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseClinicalArticle/CaseClinicalArticleLabelMapper.xml @@ -0,0 +1,23 @@ + + + + + + + case_clinical_article_label.article_label_id, + case_clinical_article_label.article_id, + case_clinical_article_label.app_iden, + case_clinical_article_label.label_name, + case_clinical_article_label.created_at, + case_clinical_article_label.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseClinicalArticle/CaseClinicalArticleMapper.xml b/sa-admin/src/main/resources/mapper/business/caseClinicalArticle/CaseClinicalArticleMapper.xml new file mode 100644 index 0000000..5250201 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseClinicalArticle/CaseClinicalArticleMapper.xml @@ -0,0 +1,83 @@ + + + + + + + case_clinical_article.article_id, + case_clinical_article.article_title, + case_clinical_article.article_status, + case_clinical_article.delete_status, + case_clinical_article.read_num, + case_clinical_article.collect_num, + case_clinical_article.comment_num, + case_clinical_article.cert_image, + case_clinical_article.push_date, + case_clinical_article.is_link, + case_clinical_article.is_link_url, + case_clinical_article.share_qrcode, + case_clinical_article.article_content, + case_clinical_article.created_at, + case_clinical_article.updated_at + + + + + + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseClinicalArticleAuthor/CaseClinicalArticleAuthorMapper.xml b/sa-admin/src/main/resources/mapper/business/caseClinicalArticleAuthor/CaseClinicalArticleAuthorMapper.xml new file mode 100644 index 0000000..e3cc2ce --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseClinicalArticleAuthor/CaseClinicalArticleAuthorMapper.xml @@ -0,0 +1,22 @@ + + + + + + + case_clinical_article_author.author_id, + case_clinical_article_author.article_id, + case_clinical_article_author.doctor_id, + case_clinical_article_author.created_at, + case_clinical_article_author.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoAuthorMapper.xml b/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoAuthorMapper.xml new file mode 100644 index 0000000..fafda9a --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoAuthorMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoLabelMapper.xml b/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoLabelMapper.xml new file mode 100644 index 0000000..123b5c8 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoLabelMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoMapper.xml b/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoMapper.xml new file mode 100644 index 0000000..0a04979 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseClinicalVideo/CaseClinicalVideoMapper.xml @@ -0,0 +1,86 @@ + + + + + + + case_clinical_video.video_id, + case_clinical_video.video_title, + case_clinical_video.video_status, + case_clinical_video.delete_status, + case_clinical_video.read_num, + case_clinical_video.collect_num, + case_clinical_video.comment_num, + case_clinical_video.video_no, + case_clinical_video.cert_image, + case_clinical_video.push_date, + case_clinical_video.is_link, + case_clinical_video.is_link_url, + case_clinical_video.share_qrcode, + case_clinical_video.created_at, + case_clinical_video.updated_at + + + + + + + + + + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeLabelMapper.xml b/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeLabelMapper.xml new file mode 100644 index 0000000..edf2ad7 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeLabelMapper.xml @@ -0,0 +1,29 @@ + + + + + + + case_exchange_label.exchange_label_id, + case_exchange_label.exchange_id, + case_exchange_label.app_iden, + case_exchange_label.label_name, + case_exchange_label.created_at, + case_exchange_label.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeMapper.xml b/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeMapper.xml new file mode 100644 index 0000000..301715c --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeMapper.xml @@ -0,0 +1,53 @@ + + + + + + + case_exchange.exchange_id, + case_exchange.user_id, + case_exchange.exchange_title, + case_exchange.exchange_status, + case_exchange.delete_status, + case_exchange.is_selected, + case_exchange.read_num, + case_exchange.collect_num, + case_exchange.comment_num, + case_exchange.push_date, + case_exchange.last_comment_time, + case_exchange.exchange_content, + case_exchange.exchange_summary, + case_exchange.exchange_content_image, + case_exchange.exchange_content_video, + case_exchange.created_at, + case_exchange.updated_at, + user.user_name, + basic_hospital.hospital_name + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeVoteMapper.xml b/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeVoteMapper.xml new file mode 100644 index 0000000..9495f5b --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeVoteMapper.xml @@ -0,0 +1,36 @@ + + + + + + + case_exchange_vote.vote_id, + case_exchange_vote.exchange_id, + case_exchange_vote.vote_title, + case_exchange_vote.end_time, + case_exchange_vote.created_at, + case_exchange_vote.updated_at + + + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeVoteOptionMapper.xml b/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeVoteOptionMapper.xml new file mode 100644 index 0000000..76f45ec --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseExchange/CaseExchangeVoteOptionMapper.xml @@ -0,0 +1,37 @@ + + + + + + + case_exchange_vote_option.option_id, + case_exchange_vote_option.vote_id, + case_exchange_vote_option.option_value, + case_exchange_vote_option.vote_num, + case_exchange_vote_option.created_at, + case_exchange_vote_option.updated_at + + + + + + + + + + + DELETE FROM case_exchange_vote_option + WHERE vote_id = #{voteId} + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseExchange/StatsCaseExchangeMapper.xml b/sa-admin/src/main/resources/mapper/business/caseExchange/StatsCaseExchangeMapper.xml new file mode 100644 index 0000000..18e09ed --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseExchange/StatsCaseExchangeMapper.xml @@ -0,0 +1,24 @@ + + + + + + + stats_case_exchange.stats_id, + stats_case_exchange.exchange_num, + stats_case_exchange.exchange_read_num, + stats_case_exchange.exchange_collect_num, + stats_case_exchange.exchange_comment_num, + stats_case_exchange.created_at, + stats_case_exchange.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/caseExchange/StatsCaseExchangeUserMapper.xml b/sa-admin/src/main/resources/mapper/business/caseExchange/StatsCaseExchangeUserMapper.xml new file mode 100644 index 0000000..0a5e693 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/caseExchange/StatsCaseExchangeUserMapper.xml @@ -0,0 +1,25 @@ + + + + + + + stats_case_exchange_user.stats_id, + stats_case_exchange_user.user_id, + stats_case_exchange_user.exchange_num, + stats_case_exchange_user.exchange_read_num, + stats_case_exchange_user.exchange_collect_num, + stats_case_exchange_user.exchange_comment_num, + stats_case_exchange_user.created_at, + stats_case_exchange_user.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/category/CategoryMapper.xml b/sa-admin/src/main/resources/mapper/business/category/CategoryMapper.xml new file mode 100644 index 0000000..ae2f4a6 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/category/CategoryMapper.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/goods/GoodsMapper.xml b/sa-admin/src/main/resources/mapper/business/goods/GoodsMapper.xml new file mode 100644 index 0000000..f7e0dfb --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/goods/GoodsMapper.xml @@ -0,0 +1,41 @@ + + + + + update t_smart_goods + set deleted_flag = #{deletedFlag} + WHERE goods_id IN + + #{item} + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/oa/bank/BankMapper.xml b/sa-admin/src/main/resources/mapper/business/oa/bank/BankMapper.xml new file mode 100644 index 0000000..13cb8a7 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/oa/bank/BankMapper.xml @@ -0,0 +1,58 @@ + + + + + UPDATE t_oa_bank + SET deleted_flag = #{deletedFlag} + WHERE bank_id = #{bankId} + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/oa/enterprise/EnterpriseEmployeeMapper.xml b/sa-admin/src/main/resources/mapper/business/oa/enterprise/EnterpriseEmployeeMapper.xml new file mode 100644 index 0000000..845fa83 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/oa/enterprise/EnterpriseEmployeeMapper.xml @@ -0,0 +1,94 @@ + + + + + + delete from t_smart_oa_enterprise_employee where enterprise_id = #{enterpriseId} and employee_id in + + #{item} + + + + + delete from t_smart_oa_enterprise_employee where employee_id = #{employeeId} + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/oa/enterprise/EnterpriseMapper.xml b/sa-admin/src/main/resources/mapper/business/oa/enterprise/EnterpriseMapper.xml new file mode 100644 index 0000000..6505869 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/oa/enterprise/EnterpriseMapper.xml @@ -0,0 +1,89 @@ + + + + + UPDATE t_smart_oa_enterprise + SET deleted_flag = #{deletedFlag} + WHERE enterprise_id = #{enterpriseId} + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/oa/invoice/InvoiceMapper.xml b/sa-admin/src/main/resources/mapper/business/oa/invoice/InvoiceMapper.xml new file mode 100644 index 0000000..c0f1b19 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/oa/invoice/InvoiceMapper.xml @@ -0,0 +1,56 @@ + + + + + UPDATE t_smart_oa_invoice + SET deleted_flag = #{deletedFlag} + WHERE invoice_id = #{invoiceId} + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/oa/notice/NoticeMapper.xml b/sa-admin/src/main/resources/mapper/business/oa/notice/NoticeMapper.xml new file mode 100644 index 0000000..04353df --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/oa/notice/NoticeMapper.xml @@ -0,0 +1,269 @@ + + + + + + + t_smart_notice.notice_id, + t_smart_notice.notice_type_id, + t_smart_notice.title, + t_smart_notice.all_visible_flag, + t_smart_notice.scheduled_publish_flag, + t_smart_notice.publish_time, + t_smart_notice.content_text, + t_smart_notice.content_html, + t_smart_notice.attachment, + t_smart_notice.page_view_count, + t_smart_notice.user_view_count, + t_smart_notice.source, + t_smart_notice.author, + t_smart_notice.document_number, + t_smart_notice.deleted_flag, + t_smart_notice.create_user_id, + t_smart_notice.update_time, + t_smart_notice.create_time + + + + + + insert into t_smart_notice_visible_range + (notice_id, data_type, data_id) + values + + ( #{noticeId} , #{item.dataType}, #{item.dataId} ) + + + + delete + from t_smart_notice_visible_range + where notice_id = #{noticeId} + + + + + + + update t_smart_notice + set deleted_flag = true + where notice_id = #{noticeId} + + + + + + + + + + + + + + insert into t_smart_notice_view_record (notice_id, employee_id, first_ip, first_user_agent, page_view_count) + values (#{noticeId}, #{employeeId}, #{ip}, #{userAgent}, #{pageViewCount}) + + + update t_smart_notice_view_record + set page_view_count = page_view_count + 1, + last_ip = #{ip}, + last_user_agent = #{userAgent} + where notice_id = #{noticeId} + and employee_id = #{employeeId} + + + update t_notice + set page_view_count = page_view_count + #{pageViewCountIncrement}, + user_view_count = user_view_count + #{userViewCountIncrement} + where notice_id = #{noticeId} + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalDoctorMapper.xml b/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalDoctorMapper.xml new file mode 100644 index 0000000..2157695 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalDoctorMapper.xml @@ -0,0 +1,30 @@ + + + + + + + stats_case_clinical_doctor.stats_id, + stats_case_clinical_doctor.doctor_id, + stats_case_clinical_doctor.article_num, + stats_case_clinical_doctor.article_read_num, + stats_case_clinical_doctor.article_collect_num, + stats_case_clinical_doctor.article_comment_num, + stats_case_clinical_doctor.last_push_date, + stats_case_clinical_doctor.video_num, + stats_case_clinical_doctor.video_read_num, + stats_case_clinical_doctor.video_collect_num, + stats_case_clinical_doctor.video_comment_num, + stats_case_clinical_doctor.created_at, + stats_case_clinical_doctor.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalHospitalMapper.xml b/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalHospitalMapper.xml new file mode 100644 index 0000000..d7d4c24 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalHospitalMapper.xml @@ -0,0 +1,30 @@ + + + + + + + stats_case_clinical_hospital.stats_id, + stats_case_clinical_hospital.hospital_id, + stats_case_clinical_hospital.article_num, + stats_case_clinical_hospital.article_read_num, + stats_case_clinical_hospital.article_collect_num, + stats_case_clinical_hospital.article_comment_num, + stats_case_clinical_hospital.last_push_date, + stats_case_clinical_hospital.video_num, + stats_case_clinical_hospital.video_read_num, + stats_case_clinical_hospital.video_collect_num, + stats_case_clinical_hospital.video_comment_num, + stats_case_clinical_hospital.created_at, + stats_case_clinical_hospital.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalLabelMapper.xml b/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalLabelMapper.xml new file mode 100644 index 0000000..b43919c --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalLabelMapper.xml @@ -0,0 +1,31 @@ + + + + + + + stats_case_clinical_label.stats_id, + stats_case_clinical_label.label_iden, + stats_case_clinical_label.label_name, + stats_case_clinical_label.article_num, + stats_case_clinical_label.article_read_num, + stats_case_clinical_label.article_collect_num, + stats_case_clinical_label.article_comment_num, + stats_case_clinical_label.last_push_date, + stats_case_clinical_label.video_num, + stats_case_clinical_label.video_read_num, + stats_case_clinical_label.video_collect_num, + stats_case_clinical_label.video_comment_num, + stats_case_clinical_label.created_at, + stats_case_clinical_label.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalMapper.xml b/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalMapper.xml new file mode 100644 index 0000000..ea560e6 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/statsCaseClinical/StatsCaseClinicalMapper.xml @@ -0,0 +1,28 @@ + + + + + + + stats_case_clinical.stats_id, + stats_case_clinical.article_num, + stats_case_clinical.article_read_num, + stats_case_clinical.article_collect_num, + stats_case_clinical.article_comment_num, + stats_case_clinical.video_num, + stats_case_clinical.video_read_num, + stats_case_clinical.video_collect_num, + stats_case_clinical.video_comment_num, + stats_case_clinical.created_at, + stats_case_clinical.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/business/user/UserMapper.xml b/sa-admin/src/main/resources/mapper/business/user/UserMapper.xml new file mode 100644 index 0000000..c5f166c --- /dev/null +++ b/sa-admin/src/main/resources/mapper/business/user/UserMapper.xml @@ -0,0 +1,47 @@ + + + + + + + user.user_id, + user.user_iden, + user.user_name, + user.user_mobile, + user.mobile_encryption, + user.status, + user.register_source, + user.open_id, + user.union_id, + user.sex, + user.avatar, + user.title, + user.department_name, + user.hospital_id, + user.address, + user.created_at, + user.updated_at + + + + + + + diff --git a/sa-admin/src/main/resources/mapper/system/PositionMapper.xml b/sa-admin/src/main/resources/mapper/system/PositionMapper.xml new file mode 100644 index 0000000..28a0ba2 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/system/PositionMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/system/department/DepartmentMapper.xml b/sa-admin/src/main/resources/mapper/system/department/DepartmentMapper.xml new file mode 100644 index 0000000..87a6663 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/system/department/DepartmentMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/system/employee/EmployeeMapper.xml b/sa-admin/src/main/resources/mapper/system/employee/EmployeeMapper.xml new file mode 100644 index 0000000..c7d7f1c --- /dev/null +++ b/sa-admin/src/main/resources/mapper/system/employee/EmployeeMapper.xml @@ -0,0 +1,200 @@ + + + + + + + + UPDATE t_smart_employee + SET disabled_flag = #{disabledFlag} + WHERE employee_id = #{employeeId} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE t_smart_employee + SET login_pwd = #{password} + WHERE employee_id = #{employeeId} + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/system/menu/MenuMapper.xml b/sa-admin/src/main/resources/mapper/system/menu/MenuMapper.xml new file mode 100644 index 0000000..f6ddeb2 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/system/menu/MenuMapper.xml @@ -0,0 +1,78 @@ + + + + + + + + update t_smart_menu + set deleted_flag = #{deletedFlag}, + update_user_id = #{updateUserId} + where menu_id = #{item} + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/system/role/RoleDataScopeMapper.xml b/sa-admin/src/main/resources/mapper/system/role/RoleDataScopeMapper.xml new file mode 100644 index 0000000..7d9da88 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/system/role/RoleDataScopeMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + DELETE FROM t_smart_role_data_scope + WHERE role_id = #{roleId} + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/system/role/RoleEmployeeMapper.xml b/sa-admin/src/main/resources/mapper/system/role/RoleEmployeeMapper.xml new file mode 100644 index 0000000..ae36643 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/system/role/RoleEmployeeMapper.xml @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE + FROM t_smart_role_employee + WHERE employee_id = #{employeeId} + + + + + DELETE + FROM t_smart_role_employee + WHERE role_id = #{roleId} + + + + DELETE + FROM t_smart_role_employee + WHERE role_id = #{roleId} + and employee_id = #{employeeId} + + + + + DELETE FROM t_smart_role_employee + WHERE role_id = #{roleId} and employee_id in + + #{item} + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/system/role/RoleMapper.xml b/sa-admin/src/main/resources/mapper/system/role/RoleMapper.xml new file mode 100644 index 0000000..4529fc0 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/system/role/RoleMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/mapper/system/role/RoleMenuMapper.xml b/sa-admin/src/main/resources/mapper/system/role/RoleMenuMapper.xml new file mode 100644 index 0000000..dba3aa8 --- /dev/null +++ b/sa-admin/src/main/resources/mapper/system/role/RoleMenuMapper.xml @@ -0,0 +1,39 @@ + + + + + delete + from t_smart_role_menu + where role_id = #{roleId} + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/pre/application.yaml b/sa-admin/src/main/resources/pre/application.yaml new file mode 100644 index 0000000..a56dcc5 --- /dev/null +++ b/sa-admin/src/main/resources/pre/application.yaml @@ -0,0 +1,22 @@ +############################################################################################################# +# # +# 为了减少重复配置,本配置文件为此sa-admin的独有配置,更多配置请查看 sa-base 项目中的 sa-base.yaml 通用配置文件。 # +# 其中此文件中配置可以覆盖 sa-base.yaml 中的通用配置,具体实现类请看类:YamlProcessor.java # +# # +############################################################################################################# + +# 项目配置: 名称、日志目录 +project: + name: sa-admin + log-directory: /home/logs/smart_admin_v3/${project.name}/${spring.profiles.active} + +# 项目端口和url根路径 +server: + port: 1024 + servlet: + context-path: / + +# 环境 +spring: + profiles: + active: '@profiles.active@' \ No newline at end of file diff --git a/sa-admin/src/main/resources/pre/log4j2-spring.xml b/sa-admin/src/main/resources/pre/log4j2-spring.xml new file mode 100644 index 0000000..10fcc1c --- /dev/null +++ b/sa-admin/src/main/resources/pre/log4j2-spring.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/prod/application.yaml b/sa-admin/src/main/resources/prod/application.yaml new file mode 100644 index 0000000..a56dcc5 --- /dev/null +++ b/sa-admin/src/main/resources/prod/application.yaml @@ -0,0 +1,22 @@ +############################################################################################################# +# # +# 为了减少重复配置,本配置文件为此sa-admin的独有配置,更多配置请查看 sa-base 项目中的 sa-base.yaml 通用配置文件。 # +# 其中此文件中配置可以覆盖 sa-base.yaml 中的通用配置,具体实现类请看类:YamlProcessor.java # +# # +############################################################################################################# + +# 项目配置: 名称、日志目录 +project: + name: sa-admin + log-directory: /home/logs/smart_admin_v3/${project.name}/${spring.profiles.active} + +# 项目端口和url根路径 +server: + port: 1024 + servlet: + context-path: / + +# 环境 +spring: + profiles: + active: '@profiles.active@' \ No newline at end of file diff --git a/sa-admin/src/main/resources/prod/log4j2-spring.xml b/sa-admin/src/main/resources/prod/log4j2-spring.xml new file mode 100644 index 0000000..822d276 --- /dev/null +++ b/sa-admin/src/main/resources/prod/log4j2-spring.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/sql/basic_hospital.sql b/sa-admin/src/main/resources/sql/basic_hospital.sql new file mode 100644 index 0000000..bdc3ee6 --- /dev/null +++ b/sa-admin/src/main/resources/sql/basic_hospital.sql @@ -0,0 +1,26 @@ +-- 创建医院表 +CREATE TABLE IF NOT EXISTS `basic_hospital` ( + `hospital_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `hospital_iden` varchar(100) DEFAULT NULL COMMENT 'app唯一标识', + `hospital_name` varchar(200) NOT NULL COMMENT '医院名称', + `source` int(11) DEFAULT NULL COMMENT '来源(2:肝胆相照 3:佳动例)', + `hospital_level` varchar(50) DEFAULT NULL COMMENT '医院等级', + `doctor_number` int(11) DEFAULT NULL COMMENT '医生数量', + `province` varchar(50) DEFAULT NULL COMMENT '省份', + `city` varchar(50) DEFAULT NULL COMMENT '城市', + `county` varchar(50) DEFAULT NULL COMMENT '区县', + `address` varchar(500) DEFAULT NULL COMMENT '地址', + `created_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updated_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', + PRIMARY KEY (`hospital_id`), + KEY `idx_hospital_name` (`hospital_name`), + KEY `idx_hospital_level` (`hospital_level`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='基础数据-医院表'; + +-- 插入一些测试数据 +INSERT INTO `basic_hospital` (`hospital_iden`, `hospital_name`, `source`, `hospital_level`, `doctor_number`, `province`, `city`, `county`, `address`) VALUES +('H001', '北京协和医院', 2, '三级甲等', 5000, '北京市', '北京市', '东城区', '北京市东城区东单帅府园1号'), +('H002', '北京大学第一医院', 2, '三级甲等', 3000, '北京市', '北京市', '西城区', '北京市西城区西什库大街8号'), +('H003', '复旦大学附属华山医院', 2, '三级甲等', 4000, '上海市', '上海市', '静安区', '上海市静安区乌鲁木齐中路12号'), +('H004', '中山大学附属第一医院', 2, '三级甲等', 3500, '广东省', '广州市', '越秀区', '广州市越秀区中山二路1号'), +('H005', '四川大学华西医院', 2, '三级甲等', 4500, '四川省', '成都市', '武侯区', '成都市武侯区国学巷37号'); \ No newline at end of file diff --git a/sa-admin/src/main/resources/static/cert/avatar.png b/sa-admin/src/main/resources/static/cert/avatar.png new file mode 100644 index 0000000..34528c5 Binary files /dev/null and b/sa-admin/src/main/resources/static/cert/avatar.png differ diff --git a/sa-admin/src/main/resources/static/cert/msyh.ttf b/sa-admin/src/main/resources/static/cert/msyh.ttf new file mode 100644 index 0000000..e0ce45d Binary files /dev/null and b/sa-admin/src/main/resources/static/cert/msyh.ttf differ diff --git a/sa-admin/src/main/resources/static/cert/seal.png b/sa-admin/src/main/resources/static/cert/seal.png new file mode 100644 index 0000000..55abdeb Binary files /dev/null and b/sa-admin/src/main/resources/static/cert/seal.png differ diff --git a/sa-admin/src/main/resources/static/cert/template.png b/sa-admin/src/main/resources/static/cert/template.png new file mode 100644 index 0000000..01372b4 Binary files /dev/null and b/sa-admin/src/main/resources/static/cert/template.png differ diff --git a/sa-admin/src/main/resources/static/cert/weChatMa.png b/sa-admin/src/main/resources/static/cert/weChatMa.png new file mode 100644 index 0000000..41d9769 Binary files /dev/null and b/sa-admin/src/main/resources/static/cert/weChatMa.png differ diff --git a/sa-admin/src/main/resources/test/application.yaml b/sa-admin/src/main/resources/test/application.yaml new file mode 100644 index 0000000..6ca92cf --- /dev/null +++ b/sa-admin/src/main/resources/test/application.yaml @@ -0,0 +1,22 @@ +############################################################################################################# +# # +# 为了减少重复配置,本配置文件为此sa-admin的独有配置,更多配置请查看 sa-base 项目中的 sa-base.yaml 通用配置文件。 # +# 其中此文件中配置可以覆盖 sa-base.yaml 中的通用配置,具体实现类请看类:YamlProcessor.java # +# # +############################################################################################################# + +# 项目配置: 名称、日志目录 +project: + name: sa-admin + log-directory: /home/project/smartadmin/test/log + +# 项目端口和url根路径 +server: + port: 11024 + servlet: + context-path: / + +# 环境 +spring: + profiles: + active: '@profiles.active@' \ No newline at end of file diff --git a/sa-admin/src/main/resources/test/log4j2-spring.xml b/sa-admin/src/main/resources/test/log4j2-spring.xml new file mode 100644 index 0000000..10fcc1c --- /dev/null +++ b/sa-admin/src/main/resources/test/log4j2-spring.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sa-admin/src/main/resources/test/spy.properties b/sa-admin/src/main/resources/test/spy.properties new file mode 100644 index 0000000..667e1ea --- /dev/null +++ b/sa-admin/src/main/resources/test/spy.properties @@ -0,0 +1,18 @@ +#相关的包 +modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory +# 日志格式 +logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger +#日志输出到控制台 +appender=com.p6spy.engine.spy.appender.StdoutLogger +# 设置 p6spy driver 代理 +deregisterdrivers=true +# 取消JDBC URL前缀 +useprefix=true +# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. +excludecategories=info,debug,result,commit,resultset +# 日期格式 +dateformat=yyyy-MM-dd HH:mm:ss +# 开启慢sql +outagedetection=true +# 慢SQL记录标准(单位秒) +outagedetectioninterval=2 \ No newline at end of file diff --git a/sa-admin/src/test/java/net/lab1024/sa/admin/AdminApplicationTest.java b/sa-admin/src/test/java/net/lab1024/sa/admin/AdminApplicationTest.java new file mode 100644 index 0000000..0d8d423 --- /dev/null +++ b/sa-admin/src/test/java/net/lab1024/sa/admin/AdminApplicationTest.java @@ -0,0 +1,25 @@ +package net.lab1024.sa.admin; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +public class AdminApplicationTest { + + @BeforeEach + public void before() { + System.out.println("----------------------- 测试开始 -----------------------"); + + } + + @AfterEach + public void after() { + System.out.println("----------------------- 测试结束 -----------------------"); + } + +} +