commit a670a2ef2b400532d286fce158db7b55af615034 Author: shahaibo <1023316923@qq.com> Date: Tue Apr 2 15:46:31 2024 +0800 TASK diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..78ab17a --- /dev/null +++ b/pom.xml @@ -0,0 +1,234 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.2.RELEASE + + + com + mixi + 0.0.1-SNAPSHOT + mixi + mixi + + 8 + 3.5.2 + 5.8.2 + 4.2.7.B + 2.0.6.graal + 1.1.1.RELEASE + 0.9.1 + 31.1-jre + + 2.4.0-b180830.0359 + 4.0.0 + 4.0.0 + 1.1.1 + 1.6.2 + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + 1.18.24 + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-configuration-processor + true + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security + spring-security-jwt + ${security.jwt.version} + + + mysql + mysql-connector-java + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis.plus.version} + + + + com.baomidou + mybatis-plus-generator + ${mybatis.plus.version} + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + + org.freemarker + freemarker + 2.3.28 + + + org.springframework.boot + spring-boot-starter-validation + + + cn.hutool + hutool-all + ${hutool.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + io.jsonwebtoken + jjwt + ${jjwt.version} + + + com.squareup.okhttp3 + okhttp + 3.14.2 + + + javax.xml.bind + jaxb-api + ${jaxb-api} + + + com.sun.xml.bind + jaxb-impl + ${jaxb-impl} + + + com.sun.xml.bind + jaxb-core + ${jaxb-core} + + + javax.activation + activation + ${activation} + + + com.github.whvcse + easy-captcha + ${easy-captcha} + + + com.google.guava + guava + ${guava.version} + + + + com.github.xiaoymin + knife4j-spring-boot-starter + 3.0.3 + + + + com.tencentcloudapi + tencentcloud-sdk-java-ses + 3.1.572 + + + + com.tencentcloudapi + tencentcloud-sdk-java-sms + 3.1.572 + + + + com.alibaba + easyexcel + 2.1.6 + + + + + + io.minio + minio + 8.0.3 + + + + org.apache.poi + poi + 5.2.1 + + + org.apache.poi + poi-ooxml + 5.2.1 + + + + com.microsoft.sqlserver + mssql-jdbc + 9.2.1.jre8 + + + + org.springframework.retry + spring-retry + 1.3.1 + + + + org.apache.logging.log4j + log4j-api + 2.14.1 + + + org.apache.logging.log4j + log4j-core + 2.14.1 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/src/main/java/com/mixi/MixiApplication.java b/src/main/java/com/mixi/MixiApplication.java new file mode 100644 index 0000000..b401642 --- /dev/null +++ b/src/main/java/com/mixi/MixiApplication.java @@ -0,0 +1,17 @@ +package com.mixi; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +@MapperScan("com.mixi.mapper") +@SpringBootApplication +@EnableScheduling +public class MixiApplication { + + public static void main(String[] args) { + SpringApplication.run(MixiApplication.class, args); + } + +} diff --git a/src/main/java/com/mixi/common/annotation/Condition.java b/src/main/java/com/mixi/common/annotation/Condition.java new file mode 100644 index 0000000..c61e68c --- /dev/null +++ b/src/main/java/com/mixi/common/annotation/Condition.java @@ -0,0 +1,19 @@ +package com.mixi.common.annotation; + +import com.mixi.common.enums.ConditionType; + +import java.lang.annotation.*; + +/** + * @author: dangweijian + * @description: 条件注解 + * @create: 2020-01-15 17:24 + **/ +@Documented +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Condition { + ConditionType type() default ConditionType.EQ; + + boolean isNull() default false; +} diff --git a/src/main/java/com/mixi/common/annotation/Order.java b/src/main/java/com/mixi/common/annotation/Order.java new file mode 100644 index 0000000..9909276 --- /dev/null +++ b/src/main/java/com/mixi/common/annotation/Order.java @@ -0,0 +1,18 @@ +package com.mixi.common.annotation; + + +import com.mixi.common.enums.OrderType; + +import java.lang.annotation.*; + +/** + * @author: dangweijian + * @description: 排序注解 + * @create: 2020-01-16 13:24 + **/ +@Documented +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Order { + OrderType order() default OrderType.DESC; +} diff --git a/src/main/java/com/mixi/common/config/FileProperties.java b/src/main/java/com/mixi/common/config/FileProperties.java new file mode 100644 index 0000000..894a5c0 --- /dev/null +++ b/src/main/java/com/mixi/common/config/FileProperties.java @@ -0,0 +1,44 @@ +package com.mixi.common.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @author yanglei + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "file") +public class FileProperties { + + private ElPath mac; + + private ElPath linux; + + private ElPath windows; + + private String linuxDomain; + + public ElPath getSys(){ + String os = System.getProperty("os.name"); + if(os.toLowerCase().startsWith("win")) { + return windows; + } else if(os.toLowerCase().startsWith("mac")){ + return mac; + } + return linux; + } + public String getLinuxDomain(){ + String os = System.getProperty("os.name"); + if((!os.toLowerCase().startsWith("win") )&& (!os.toLowerCase().startsWith("mac"))) { + return linuxDomain; + } + return null; + } + + @Data + public static class ElPath{ + private String path; + } +} diff --git a/src/main/java/com/mixi/common/config/MinIoClientConfig.java b/src/main/java/com/mixi/common/config/MinIoClientConfig.java new file mode 100644 index 0000000..650fd46 --- /dev/null +++ b/src/main/java/com/mixi/common/config/MinIoClientConfig.java @@ -0,0 +1,34 @@ +package com.mixi.common.config; + +import io.minio.MinioClient; +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +@Data +@Component +public class MinIoClientConfig { + @Value("${minio.endpoint}") + private String endpoint; + @Value("${minio.accessKey}") + private String accessKey; + @Value("${minio.secretKey}") + private String secretKey; + + /** + * 注入minio 客户端 + * + * @return + */ + @Bean + public MinioClient minioClient() { + + return MinioClient.builder() + .endpoint(endpoint) + .credentials(accessKey, secretKey) + .build(); + } + +} + diff --git a/src/main/java/com/mixi/common/config/MybatisPlusGenerate.java b/src/main/java/com/mixi/common/config/MybatisPlusGenerate.java new file mode 100644 index 0000000..36383c6 --- /dev/null +++ b/src/main/java/com/mixi/common/config/MybatisPlusGenerate.java @@ -0,0 +1,227 @@ +package com.mixi.common.config; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.baomidou.mybatisplus.generator.FastAutoGenerator; +import com.baomidou.mybatisplus.generator.config.OutputFile; +import com.baomidou.mybatisplus.generator.config.rules.DateType; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; +import com.baomidou.mybatisplus.generator.fill.Column; +import com.mixi.common.config.mybatis.plus.CommonMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.util.*; + +/** + * 苞米豆代码自动生成器 可生成 controller service entity mapper + */ +@Slf4j +public class MybatisPlusGenerate { + // TODO:配置数据库信息(需要修改为自己的) +// private static final String URL = "jdbc:mysql://18.167.251.121:3306/mixi?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"; + private static final String URL = "jdbc:mysql://localhost:3306/gxyd_5a_theme?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"; + private static final String USERNAME = "root"; +// private static final String PASSWORD = "QWa998345"; + private static final String PASSWORD = "QWa998345"; + // TODO:项目根目录(需要修改成自己的) + private static final String PROJECT_ROOT_PATH = "D:\\codeManager\\code\\mixi"; + //TODO:这里需要注意IOT-admin是项目模块名 如果是多模块模式就需要加上模块名路径 + private static final String BASE_PATH = PROJECT_ROOT_PATH + "\\src\\main\\java\\com\\mixi"; + private static final String PARENT_PACKAGE_NAME = "\\com.mixi"; + private static final String PACKAGE_GENERATE_LOCATION = "D:\\codeManager\\generate"; + + + // 代码生成方法 + @SuppressWarnings("all") + private static void codeGenerator() { + // 六个文件的路径 + String entityPath = BASE_PATH + "\\mapper\\entity"; + String mapperPath = BASE_PATH + "\\mapper\\"; + String mapperXmlPath = PROJECT_ROOT_PATH + "\\src\\main\\resources\\mapper"; + String servicePath = BASE_PATH + "\\service"; + //暂时不生成impl +// String serviceImplPath = BASE_PATH + "/service/impl"; + String controllerPath = BASE_PATH + "\\controller"; + + FastAutoGenerator.create(URL, "root", PASSWORD) + .globalConfig(builder -> { + builder.author("yanglei") // 设置作者 + // 开启覆盖已生成的文件 + .fileOverride() +// // 禁止打开输出目录 +// .disableOpenDir() + // 开启swagger2。注释掉则默认关闭。 + .enableSwagger() +// // 时间策略 + .dateType(DateType.TIME_PACK) +// // 时间格式 + .commentDate("yyyy-MM-dd") + //鼠标右击蓝色java目录,选择Copy Path... 选择 Absolute Path 即可复制路径,粘贴到下面即可 + .outputDir(PACKAGE_GENERATE_LOCATION); // 指定输出目录 + }) + .packageConfig(builder -> { + // 阶段1:各个文件的包名设置,用来拼接每个java文件的第一句:package com.XXX.XXX.XXX.xxx; + builder.parent(PARENT_PACKAGE_NAME) // 设置父包名 +// .moduleName("") // 设置父包模块名 需要你就设置 + // 父包名配置 + .entity("mapper.entity") + .mapper("mapper") + .xml("mapper.xml") + .service("service") +// .serviceImpl("service.impl") + .controller("controller") + .other("other") +// .pathInfo(Collections.singletonMap(OutputFile.mapper, mapperPath)); // 设置mapperXml生成路径 +// .pathInfo(new HashMap() {{ +// // 实体类的保存路径 +// put(OutputFile.entity, entityPath); +// // mapper接口的保存路径 +// put(OutputFile.mapper, mapperPath); +// // mapper.xml文件的保存路径 +// put(OutputFile.xml, mapperXmlPath); +// // service层接口的保存路径 +// put(OutputFile.service, servicePath); +//// // service层接口实现类的保存路径 +//// put(OutputFile.serviceImpl, serviceImplPath); +// // 控制类的保存路径 +// put(OutputFile.controller, controllerPath); +// }}); // 设置mapperXml生成路径 + .pathInfo(new HashMap() {{ + // 实体类的保存路径 +// put(OutputFile.entity, PARENT_PACKAGE_NAME+"\\mapper\\entity"); + // mapper接口的保存路径 +// put(OutputFile.mapper, PACKAGE_GENERATE_LOCATION+PARENT_PACKAGE_NAME+"\\mapper"); +// // mapper.xml文件的保存路径 +// put(OutputFile.xml, PARENT_PACKAGE_NAME+"\\mapper2"); +//// // service层接口的保存路径 +// put(OutputFile.service, PARENT_PACKAGE_NAME+"\\service"); +// // // service层接口实现类的保存路径 +// // put(OutputFile.serviceImpl, serviceImplPath); +// // 控制类的保存路径 +// put(OutputFile.controller, PARENT_PACKAGE_NAME+"\\controller"); + }}); // 设置mapperXml生成路径 + }) + .strategyConfig(builder -> { +// builder.addInclude(getTables("t_product,t_product_batch,t_product_stock," + +// "t_attribute_type,t_attribute_value,t_product_assortment"))// 设置需要生成的表名 + builder.addInclude(getTables("t_behavior_analysis"))// 设置需要生成的表名,数组 逗号分割 + // 阶段1:Entity实体类策略配置 + .entityBuilder() + // 设置父类。会在生成的实体类名后:extends BaseEntity +// .superClass(BaseEntity.class) + // 禁用生成 serialVersionUID。(不推荐禁用) + // .disableSerialVersionUID() + // 开启生成字段常量。 + // 会在实体类末尾生成一系列 [public static final String NICKNAME = "nickname";] 的语句。(一般在写wapper时,会用到) + // .enableColumnConstant() + // 开启链式模型。 + // 会在实体类前添加 [@Accessors(chain = true)] 注解。用法如 [User user=new User().setAge(31).setName("snzl");](这是Lombok的注解,需要添加Lombok依赖) + .enableChainModel() + // 开启 lombok 模型。 + // 会在实体类前添加 [@Getter] 和 [@Setter] 注解。(这是Lombok的注解,需要添加Lombok依赖) + .enableLombok() + // 开启 Boolean 类型字段移除 is 前缀。 + // .enableRemoveIsPrefix() + // 开启生成实体时生成字段注解。 + // 会在实体类的属性前,添加[@TableField("nickname")] +// .enableTableFieldAnnotation() + // 逻辑删除字段名(数据库)。 +// .logicDeleteColumnName("is_delete") + // 逻辑删除属性名(实体)。 + // 会在实体类的该字段属性前加注解[@TableLogic] +// .logicDeletePropertyName("isDelete") + // 数据库表映射到实体的命名策略(默认下划线转驼峰)。一般不用设置 + // .naming(NamingStrategy.underline_to_camel) + // 数据库表字段映射到实体的命名策略(默认为 null,未指定按照 naming 执行)。一般不用设置 + // .columnNaming(NamingStrategy.underline_to_camel) + // 添加父类公共字段。 + // 这些字段不会出现在新增的实体类中。 +// .addSuperEntityColumns("id", "delete_time") + // 添加忽略字段。 + // 这些字段不会出现在新增的实体类中。 + // .addIgnoreColumns("password") + // 添加表字段填充 + // 会在实体类的该字段上追加注解[@TableField(value = "create_time", fill = FieldFill.INSERT)] + .addTableFills(new Column("create_date", FieldFill.INSERT)) + // 会在实体类的该字段上追加注解[@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)] + .addTableFills(new Column("update_date", FieldFill.INSERT_UPDATE)) + // 全局主键类型。如果MySQL主键设置为自增,则不需要设置此项。 + // .idType(IdType.AUTO) + // 格式化文件名称。 + // 如果不设置,如表[sys_user]的实体类名是[SysUser]。设置成下面这样,将是[SysUserEntity] +// .formatFileName("%sEntity") +// builder.addTablePrefix("t_", "c_"). // 设置过滤表前缀 卡尼的表是否存在前缀 + + // 阶段2:Mapper策略配置 + .mapperBuilder() + // 设置父类 + // 会在mapper接口方法集成[extends BaseMapper] + .superClass(CommonMapper.class) + // 开启 @Mapper 注解。 + // 会在mapper接口上添加注解[@Mapper] + .enableMapperAnnotation() + // 启用 BaseResultMap 生成。 + // 会在mapper.xml文件生成[通用查询映射结果]配置。 + .enableBaseResultMap() + // 启用 BaseColumnList。 + // 会在mapper.xml文件生成[通用查询结果列 ]配置 + .enableBaseColumnList() + // 设置缓存实现类 + // .cache(MyMapperCache.class) + // 格式化 mapper 文件名称。 + // 如果不设置,如表[sys_user],默认的文件名是[SysUserMapper]。写成下面这种形式后,将变成[SysUserDao]。 +// .formatMapperFileName("%sMapper") + // 格式化 xml 实现类文件名称。 + // 如果不设置,如表[sys_user],默认的文件名是[SysUserMapper.xml],写成下面这种形式后,将变成[SysUserXml.xml]。 + // .formatXmlFileName("%sXml") + + // 阶段3:Service策略配置 + .serviceBuilder() + // 设置 service 接口父类 + .superServiceClass(ServiceImpl.class) + // 设置 service 实现类父类 + // .superServiceImplClass(BaseServiceImpl.class) + // 格式化 service 接口文件名称 + // 如果不设置,如表[sys_user],默认的是[ISysUserService]。写成下面这种形式后,将变成[SysUserService]。 + .formatServiceFileName("%sService") + // 格式化 service 实现类文件名称 + // 如果不设置,如表[sys_user],默认的是[SysUserServiceImpl]。 + // .formatServiceImplFileName("%sServiceImpl") + + // 阶段4:Controller策略配置 + .controllerBuilder() + // 设置父类。 + // 会集成此父类。 + // .superClass(BaseController.class) + // 开启生成 @RestController 控制器 + // 会在控制类中加[@RestController]注解。 + .enableRestStyle() + // 开启驼峰转连字符 + .enableHyphenStyle() + + // 最后:构建 + .build(); + }) + .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 + .execute(); + log.info("本地表生成完毕!"); + } + // 执行main方法 + public static void main(String[] args) { + codeGenerator(); + } + + /** + * @Description 处理控制台输入all情况 + * @Params [tables] + * @Return java.util.List + * @Author Corey + * @Date 2022/8/8 18:55 + */ + private static List getTables(String tables) { + return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(",")); + } +} diff --git a/src/main/java/com/mixi/common/config/RsaProperties.java b/src/main/java/com/mixi/common/config/RsaProperties.java new file mode 100644 index 0000000..981f487 --- /dev/null +++ b/src/main/java/com/mixi/common/config/RsaProperties.java @@ -0,0 +1,17 @@ +package com.mixi.common.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Data +@Component +public class RsaProperties { + + public static String privateKey; + + @Value("${rsa.private_key}") + public void setPrivateKey(String privateKey) { + RsaProperties.privateKey = privateKey; + } +} diff --git a/src/main/java/com/mixi/common/config/WebConfig.java b/src/main/java/com/mixi/common/config/WebConfig.java new file mode 100644 index 0000000..c75f533 --- /dev/null +++ b/src/main/java/com/mixi/common/config/WebConfig.java @@ -0,0 +1,33 @@ +package com.mixi.common.config; + + +import org.hibernate.validator.HibernateValidator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +@Configuration +public class WebConfig { + + @Bean + public Validator validator() { + ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class) + .configure() + //failFast为true出现校验失败的情况,立即结束校验,不再进行后续的校验 + .failFast(true) + .buildValidatorFactory(); + + return validatorFactory.getValidator(); + } + + @Bean + public MethodValidationPostProcessor methodValidationPostProcessor() { + MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor(); + methodValidationPostProcessor.setValidator(validator()); + return methodValidationPostProcessor; + } +} diff --git a/src/main/java/com/mixi/common/config/captcha/LoginCode.java b/src/main/java/com/mixi/common/config/captcha/LoginCode.java new file mode 100644 index 0000000..f40be12 --- /dev/null +++ b/src/main/java/com/mixi/common/config/captcha/LoginCode.java @@ -0,0 +1,40 @@ +package com.mixi.common.config.captcha; + +import lombok.Data; + +@Data +public class LoginCode { + + /** + * 验证码配置 + */ + private LoginCodeEnum codeType = LoginCodeEnum.arithmetic; + /** + * 验证码有效期 分钟 + */ + private Long expiration = 2L; + /** + * 验证码内容长度 + */ + private int length = 2; + /** + * 验证码宽度 + */ + private int width = 111; + /** + * 验证码高度 + */ + private int height = 36; + /** + * 验证码字体 + */ + private String fontName; + /** + * 字体大小 + */ + private int fontSize = 25; + + public LoginCodeEnum getCodeType() { + return codeType; + } +} diff --git a/src/main/java/com/mixi/common/config/captcha/LoginCodeEnum.java b/src/main/java/com/mixi/common/config/captcha/LoginCodeEnum.java new file mode 100644 index 0000000..74972a1 --- /dev/null +++ b/src/main/java/com/mixi/common/config/captcha/LoginCodeEnum.java @@ -0,0 +1,21 @@ +package com.mixi.common.config.captcha; + +public enum LoginCodeEnum { + /** + * 算数 + */ + arithmetic, + /** + * 中文 + */ + chinese, + /** + * 中文闪图 + */ + chinese_gif, + /** + * 闪图 + */ + gif, + spec +} diff --git a/src/main/java/com/mixi/common/config/exception/BusinessException.java b/src/main/java/com/mixi/common/config/exception/BusinessException.java new file mode 100644 index 0000000..97a862b --- /dev/null +++ b/src/main/java/com/mixi/common/config/exception/BusinessException.java @@ -0,0 +1,28 @@ +package com.mixi.common.config.exception; + +import com.mixi.common.response.ResultEnum; +import lombok.Data; + +/** + * @author: dangweijian + * @description: 业务异常 + * @create: 2020-01-01 17:24 + **/ +@Data +public class BusinessException extends RuntimeException { + + private Integer code; + private String msg; + + public BusinessException(ResultEnum resultEnum){ + super(resultEnum.getMsg()); + this.code = resultEnum.getCode(); + this.msg = resultEnum.getMsg(); + } + + public BusinessException(String msg) { + super(msg); + this.code = ResultEnum.FAIL.getCode(); + this.msg = msg; + } +} diff --git a/src/main/java/com/mixi/common/config/exception/ExceptionCatch.java b/src/main/java/com/mixi/common/config/exception/ExceptionCatch.java new file mode 100644 index 0000000..cd55566 --- /dev/null +++ b/src/main/java/com/mixi/common/config/exception/ExceptionCatch.java @@ -0,0 +1,85 @@ +package com.mixi.common.config.exception; + +import com.mixi.common.response.Response; +import com.google.common.collect.ImmutableMap; +import com.mixi.common.response.ResultEnum; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.BindException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * @author: dangweijian + * @description: 全局异常捕获 + * @create: 2019-12-03 10:24 + **/ +@Slf4j +@ControllerAdvice +public class ExceptionCatch { + + /** + * 线程安全,且构建后不可更改 + */ + private static ImmutableMap, ResultEnum> EXCEPTIONS; + + /** + * 用于构建ImmutableMap + */ + private static ImmutableMap.Builder, ResultEnum> builder = ImmutableMap.builder(); + + @ResponseBody + @ExceptionHandler(BusinessException.class) + public Response businessExceptionCatch(BusinessException e) { + log.error("发生业务异常,code:[{}],msg:[{}]", e.getCode(), e.getMsg(), e); + return Response.error(e.getCode(), e.getMsg()); + } + + @ResponseBody + @ExceptionHandler(Exception.class) + public Response exceptionCatch(Exception e) { + log.error("发生系统异常,message:[{}]", e.getMessage(), e); + //如果ImmutableMap集合为空,构建ImmutableMap + if (EXCEPTIONS == null || EXCEPTIONS.size() == 0) { + EXCEPTIONS = builder.build(); + } + //获取不可预知异常自定义错误码 + if (EXCEPTIONS != null) { + ResultEnum resultEnum = EXCEPTIONS.get(e.getClass()); + if (resultEnum != null) { + return Response.error(resultEnum.getCode(), resultEnum.getMsg()); + } + } + return Response.error(ResultEnum.ERROR.getCode(), e.getMessage()==null?ResultEnum.ERROR.getMsg():e.getMessage()); + } + + /** + * 处理参数校验异常 + * @param e + * @return ResponseData + */ + @ResponseBody + @ExceptionHandler(BindException.class) + public Response bindExceptionHandler(BindException e) { + log.error("参数错误bind:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); + return Response.fail(ResultEnum.FAIL.getCode(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); + } + + /** + * 处理参数校验异常 + * @param e + * @return ResponseData + */ + @ResponseBody + @ExceptionHandler(MethodArgumentNotValidException.class) + public Response methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) { + log.error("参数错误bind:{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); + return Response.fail(ResultEnum.FAIL.getCode(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); + } + + //初始化,不可预知异常自定义错误编码 + static { +// builder.put(FileNotFoundException.class, ResultEnum.FILE_NOT_EXIST); + } +} diff --git a/src/main/java/com/mixi/common/config/mybatis/plus/CommonMapper.java b/src/main/java/com/mixi/common/config/mybatis/plus/CommonMapper.java new file mode 100644 index 0000000..0edd928 --- /dev/null +++ b/src/main/java/com/mixi/common/config/mybatis/plus/CommonMapper.java @@ -0,0 +1,12 @@ +package com.mixi.common.config.mybatis.plus; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import org.apache.ibatis.annotations.Param; + +public interface CommonMapper extends BaseMapper { + + IPage voPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper); +} diff --git a/src/main/java/com/mixi/common/config/mybatis/plus/CommonServiceImpl.java b/src/main/java/com/mixi/common/config/mybatis/plus/CommonServiceImpl.java new file mode 100644 index 0000000..46675ab --- /dev/null +++ b/src/main/java/com/mixi/common/config/mybatis/plus/CommonServiceImpl.java @@ -0,0 +1,48 @@ +package com.mixi.common.config.mybatis.plus; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mixi.common.response.PageResponse; +import com.mixi.common.response.Response; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + + +public class CommonServiceImpl, T, E> extends ServiceImpl { + + public PageResponse voPage(QueryCriteria criteria) { + IPage tPage = baseMapper.voPage(new Page<>(criteria.getPage(), criteria.getLimit()), criteria.buildWrapper()); + if (criteria.getMapper() != null && tPage != null && CollUtil.isNotEmpty(tPage.getRecords())) { + List convert = convert(tPage, criteria.getMapper(), criteria); + Response> response = Response.success(convert); + PageResponse pageResponse = new PageResponse<>(response, tPage.getCurrent(), tPage.getSize(), tPage.getTotal(), tPage.getPages()); + if (criteria.getPeekAllAfter() != null) { + Consumer> peekAllAfter = criteria.getPeekAllAfter(); + peekAllAfter.accept(pageResponse.getData()); + } + return pageResponse; + } + PageResponse pageResponse = new PageResponse<>(null, criteria.getPage(), criteria.getLimit(), 0, 0); + if (criteria.getPeekAllAfter() != null) { + Consumer> peekAllAfter = criteria.getPeekAllAfter(); + peekAllAfter.accept(pageResponse.getData()); + } + return pageResponse; + } + + List convert(IPage page, Function mapper, QueryCriteria criteria) { + if (criteria.getPeekBefore() != null && criteria.getPeekAfter() != null) { + return page.getRecords().stream().peek(criteria.getPeekBefore()).map(mapper).peek(criteria.getPeekAfter()).collect(Collectors.toList()); + } else if (criteria.getPeekBefore() != null && criteria.getPeekAfter() == null) { + return page.getRecords().stream().peek(criteria.getPeekBefore()).map(mapper).collect(Collectors.toList()); + } else if (criteria.getPeekBefore() == null && criteria.getPeekAfter() != null) { + return page.getRecords().stream().map(mapper).peek(criteria.getPeekAfter()).collect(Collectors.toList()); + } + return page.getRecords().stream().map(mapper).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/mixi/common/config/mybatis/plus/CustomerSqlInjector.java b/src/main/java/com/mixi/common/config/mybatis/plus/CustomerSqlInjector.java new file mode 100644 index 0000000..3a04cec --- /dev/null +++ b/src/main/java/com/mixi/common/config/mybatis/plus/CustomerSqlInjector.java @@ -0,0 +1,19 @@ +package com.mixi.common.config.mybatis.plus; + +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Configuration +public class CustomerSqlInjector extends DefaultSqlInjector { + + @Override + public List getMethodList(Class mapperClass, TableInfo tableInfo) { + List methodList = super.getMethodList(mapperClass, tableInfo); + methodList.add(new SelectVoPage()); + return methodList; + } +} diff --git a/src/main/java/com/mixi/common/config/mybatis/plus/MybatisPlusConfig.java b/src/main/java/com/mixi/common/config/mybatis/plus/MybatisPlusConfig.java new file mode 100644 index 0000000..72eeff4 --- /dev/null +++ b/src/main/java/com/mixi/common/config/mybatis/plus/MybatisPlusConfig.java @@ -0,0 +1,20 @@ +package com.mixi.common.config.mybatis.plus; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScan("com.intelligent.curtain.mapper") +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } +} diff --git a/src/main/java/com/mixi/common/config/mybatis/plus/QueryCriteria.java b/src/main/java/com/mixi/common/config/mybatis/plus/QueryCriteria.java new file mode 100644 index 0000000..31d5e28 --- /dev/null +++ b/src/main/java/com/mixi/common/config/mybatis/plus/QueryCriteria.java @@ -0,0 +1,83 @@ +package com.mixi.common.config.mybatis.plus; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.mixi.common.annotation.Condition; +import com.mixi.common.annotation.Order; +import com.mixi.common.utils.ConvertUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * @author: dangweijian + * @description: + * @create: 2020-09-14 15:47 + **/ +@Data +@Slf4j +public abstract class QueryCriteria { + + private long page = 1; + private long limit = 10; + private Function mapper; + private Consumer> appendWrapper; + private Consumer peekBefore; + private Consumer peekAfter; + private Consumer> peekAllAfter; + + public QueryCriteria(Function mapper) { + this.mapper = mapper; + } + + public QueryWrapper buildWrapper(){ + QueryWrapper wrapper = new QueryWrapper<>(); + Field[] fields = this.getClass().getDeclaredFields(); + for (Field field : fields) { + Condition condition = field.getAnnotation(Condition.class); + if(condition != null){ + field.setAccessible(true); + Object value = null; + try { + value = field.get(this); + } catch (IllegalAccessException e) { + log.warn("reflection anomaly!"); + } + if(!StrUtil.isEmptyIfStr(value)){ + switch (condition.type()){ + case EQ: + wrapper.eq(ConvertUtil.humpToLine2(field.getName()), value); + break; + case LIKE: + wrapper.like(ConvertUtil.humpToLine2(field.getName()), value); + case BETWEEN: + if(value instanceof Collection && ((List) value).size() >= 2){ + wrapper.between(ConvertUtil.humpToLine2(field.getName()), ((List)value).get(0), ((List)value).get(1)); + } + } + }else if(condition.isNull()){ + wrapper.isNull(ConvertUtil.humpToLine2(field.getName())); + } + } + Order order = field.getAnnotation(Order.class); + if(order != null){ + if(!StrUtil.isEmptyIfStr(order.order())){ + switch (order.order()){ + case DESC: + wrapper.orderByDesc(ConvertUtil.humpToLine2(field.getName())); + break; + case ASC: + wrapper.orderByAsc(ConvertUtil.humpToLine2(field.getName())); + } + } + } + } + wrapper.func(this.getAppendWrapper() != null, this.getAppendWrapper()); + return wrapper; + } +} diff --git a/src/main/java/com/mixi/common/config/mybatis/plus/SelectVoPage.java b/src/main/java/com/mixi/common/config/mybatis/plus/SelectVoPage.java new file mode 100644 index 0000000..1cf08d7 --- /dev/null +++ b/src/main/java/com/mixi/common/config/mybatis/plus/SelectVoPage.java @@ -0,0 +1,22 @@ +package com.mixi.common.config.mybatis.plus; + +import com.baomidou.mybatisplus.core.enums.SqlMethod; +import com.baomidou.mybatisplus.core.injector.AbstractMethod; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlSource; + +public class SelectVoPage extends AbstractMethod { + + private static final String MAPPER_METHOD = "voPage"; + + public SelectVoPage() { + super(MAPPER_METHOD); + } + + public MappedStatement injectMappedStatement(Class mapperClass, Class modelClass, TableInfo tableInfo) { + String sql = String.format(SqlMethod.SELECT_PAGE.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlOrderBy(tableInfo), this.sqlComment()); + SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass); + return this.addSelectMappedStatementForTable(mapperClass, MAPPER_METHOD, sqlSource, tableInfo); + } +} diff --git a/src/main/java/com/mixi/common/config/swagger/Knife4jConfiguration.java b/src/main/java/com/mixi/common/config/swagger/Knife4jConfiguration.java new file mode 100644 index 0000000..f82630b --- /dev/null +++ b/src/main/java/com/mixi/common/config/swagger/Knife4jConfiguration.java @@ -0,0 +1,33 @@ +package com.mixi.common.config.swagger; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; + +@Configuration +@EnableSwagger2WebMvc +public class Knife4jConfiguration { + + @Bean(value = "MixiApis") + public Docket gxyd5aThemeApis() { + Docket docket=new Docket(DocumentationType.SWAGGER_2) + .apiInfo(new ApiInfoBuilder() + .description("Mixi接口文档文档") + .termsOfServiceUrl("暂无") + .version("1.0") + .build()) + //分组名称 + .groupName("1.0") + .select() + //这里指定Controller扫描包路径 + .apis(RequestHandlerSelectors.basePackage("com.mixi.controller")) + .paths(PathSelectors.any()) + .build(); + return docket; + } +} diff --git a/src/main/java/com/mixi/common/constant/ExceptionConstant.java b/src/main/java/com/mixi/common/constant/ExceptionConstant.java new file mode 100644 index 0000000..4a0ed55 --- /dev/null +++ b/src/main/java/com/mixi/common/constant/ExceptionConstant.java @@ -0,0 +1,9 @@ +package com.mixi.common.constant; + +/** + * @author yanglei + * 异常类常量 + */ +public class ExceptionConstant { + public static final int DATA_SIZE_LIIMIT = 500; +} diff --git a/src/main/java/com/mixi/common/constant/TokenConstant.java b/src/main/java/com/mixi/common/constant/TokenConstant.java new file mode 100644 index 0000000..d8c981b --- /dev/null +++ b/src/main/java/com/mixi/common/constant/TokenConstant.java @@ -0,0 +1,14 @@ +package com.mixi.common.constant; + +/** + * @author yanglei + * 异常类常量 + */ +public class TokenConstant { + /** + * 固定session + */ + public static final String FIX_SESSION = "qrLS_003b0ff46b42356f_40be06f160c74616b815c680f3cca1f3"; + + public static final String PERMISSIONS = "9672233956"; +} diff --git a/src/main/java/com/mixi/common/context/UserContext.java b/src/main/java/com/mixi/common/context/UserContext.java new file mode 100644 index 0000000..682e189 --- /dev/null +++ b/src/main/java/com/mixi/common/context/UserContext.java @@ -0,0 +1,19 @@ +package com.mixi.common.context; + + +import com.mixi.model.vo.AuthPrincipalVo; + +public class UserContext { + private static ThreadLocal userHolder= new ThreadLocal(); + + public static AuthPrincipalVo getUserHolder() { + return userHolder.get(); + } + public static void delete() { + userHolder.remove(); + } + + public static void setUserHolder(AuthPrincipalVo authPrincipalVo) { + userHolder.set(authPrincipalVo); + } +} diff --git a/src/main/java/com/mixi/common/enums/ConditionType.java b/src/main/java/com/mixi/common/enums/ConditionType.java new file mode 100644 index 0000000..7c2db1b --- /dev/null +++ b/src/main/java/com/mixi/common/enums/ConditionType.java @@ -0,0 +1,10 @@ +package com.mixi.common.enums; + +/** + * @author: dangweijian + * @description: 分页条件类型 + * @create: 2020-01-14 17:33 + **/ +public enum ConditionType { + EQ,LIKE,BETWEEN; +} diff --git a/src/main/java/com/mixi/common/enums/DataScope.java b/src/main/java/com/mixi/common/enums/DataScope.java new file mode 100644 index 0000000..afa7c97 --- /dev/null +++ b/src/main/java/com/mixi/common/enums/DataScope.java @@ -0,0 +1,21 @@ +package com.mixi.common.enums; + +public enum DataScope { + + ALL("全部"), + DEPT("部门"); + + private String desc; + + DataScope(String desc) { + this.desc = desc; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/src/main/java/com/mixi/common/enums/LabelTypeEnum.java b/src/main/java/com/mixi/common/enums/LabelTypeEnum.java new file mode 100644 index 0000000..8ea81ad --- /dev/null +++ b/src/main/java/com/mixi/common/enums/LabelTypeEnum.java @@ -0,0 +1,33 @@ +package com.mixi.common.enums; + +import lombok.AllArgsConstructor; + +import java.util.stream.Stream; + +/** + * @author: yanglei + * @description: 标签类型 + * @create: 2023-3-6 17:33 + **/ +@AllArgsConstructor +public enum LabelTypeEnum { + /** + * 自定义标签 + */ + CUSTOM("Custom Label"), + /** + * 新品 + */ + NEW_PRODUCT("New product"), + /** + * 折扣 + */ + SALE("Sale"),; + + private String desc; + + + public static LabelTypeEnum of(String name){ + return Stream.of(LabelTypeEnum.values()).filter(v ->v.name().equals(name)).findFirst().orElse(null); + } +} diff --git a/src/main/java/com/mixi/common/enums/OperationTypeEnum.java b/src/main/java/com/mixi/common/enums/OperationTypeEnum.java new file mode 100644 index 0000000..f72985d --- /dev/null +++ b/src/main/java/com/mixi/common/enums/OperationTypeEnum.java @@ -0,0 +1,27 @@ +package com.mixi.common.enums; + +import java.util.stream.Stream; + +/** + * @author: yanglei + * @description: 操作类型 登入 忘记密码 + * @create: 2022-8-10 17:33 + **/ +public enum OperationTypeEnum { + /** + *登入 + */ + LOGIN, + /** + * 注册 + */ + REGISTER, + /** + * 忘记密码 + */ + FORGET_PWD; + + public static OperationTypeEnum of(String name){ + return Stream.of(OperationTypeEnum.values()).filter(v ->v.name().equals(name)).findFirst().orElse(null); + } +} diff --git a/src/main/java/com/mixi/common/enums/OrderType.java b/src/main/java/com/mixi/common/enums/OrderType.java new file mode 100644 index 0000000..088d21f --- /dev/null +++ b/src/main/java/com/mixi/common/enums/OrderType.java @@ -0,0 +1,10 @@ +package com.mixi.common.enums; + +/** + * @author: dangweijian + * @description: 排序类型 + * @create: 2020-01-14 17:33 + **/ +public enum OrderType { + DESC,ASC; +} diff --git a/src/main/java/com/mixi/common/enums/RolePermissionOperationEnum.java b/src/main/java/com/mixi/common/enums/RolePermissionOperationEnum.java new file mode 100644 index 0000000..99b3706 --- /dev/null +++ b/src/main/java/com/mixi/common/enums/RolePermissionOperationEnum.java @@ -0,0 +1,45 @@ +package com.mixi.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author: yanglei + * @description: 角色权限操作 + * @create: 2023-3-6 17:33 + **/ +@Getter +@AllArgsConstructor +@NoArgsConstructor +public enum RolePermissionOperationEnum { + /** + * 详情 + */ + DETAIL("Details", 1), + /** + * 添加 + */ + ADD("Add", 2), + /** + * 编辑 + */ + EDIT("Edit", 3), + /** + * 删除 + */ + DELETE("Delete", 4), + ; + + private String desc; + private Integer sort; + + + public static List ofCodeList() { + return Stream.of(RolePermissionOperationEnum.values()).map(RolePermissionOperationEnum::name).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/mixi/common/enums/RolePermissionResourceEnum.java b/src/main/java/com/mixi/common/enums/RolePermissionResourceEnum.java new file mode 100644 index 0000000..3821406 --- /dev/null +++ b/src/main/java/com/mixi/common/enums/RolePermissionResourceEnum.java @@ -0,0 +1,162 @@ +package com.mixi.common.enums; + +import com.google.common.collect.Lists; +import com.mixi.model.vo.RolePermission2OperationVO; +import com.mixi.model.vo.RolePermission2VO; +import com.mixi.model.vo.RolePermission1VO; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author: yanglei + * @description: 角色权限菜单 + * @create: 2023-3-7 17:33 + **/ +@Getter +@AllArgsConstructor +@NoArgsConstructor +public enum RolePermissionResourceEnum { + /** + * 工作台 + */ + WORK_BENCH("Workdesk","WORK_BENCH",null,null,null,1), + /** + * 商品列表 + */ + PRODUCT_LIST("Product Management","PRODUCT_MANAGER","Product List","PRODUCT_LIST",RolePermissionOperationEnum.ofCodeList(),2), + /** + * 门店列表 + */ + STORE_LIST("Store Management","STORE_MANAGER","Store List","STORE_LIST",null,3), + /** + * 标签列表 + */ + LABEL_LIST("Label Management","LABEL_MANAGER","Label List","LABEL_LIST",null,4), + /** + * 销售报表 + */ + SELLER_REPORT("Sales Report","SELLER_REPORT","Sales Report","SELLER_REPORT",null,5), + /** + * 客户信息 + */ + CUSTOMER_INFO("Customer Management","CUSTOMER_MANAGER","Customer Information","CUSTOMER_INFO",null,6), + /** + * 客户浏览记录 + */ + CUSTOMER_VISIT("Customer Management","CUSTOMER_MANAGER","Customer Browsing History","CUSTOMER_VISIT",null,7), + /** + * 客户购买记录 + */ + CUSTOMER_PURCHASE("Customer Management","CUSTOMER_MANAGER","Customer Purchase History","CUSTOMER_PURCHASE ",null,8), + /** + * 用户管理 + */ + USER_MANAGER("System Management","SYS_MANAGER","User Management","USER_MANAGER",null,9), + /** + * 角色管理 + */ + ROLE_MANAGER("System Management","SYS_MANAGER","Role Management","ROLE_MANAGER",null,10), + /** + * Mi-Tu 报表 + */ + MI_TU_EXPORT("Mi-Tu Export","MI_TU_EXPORT",null,null,null,11), + ; + + /** + * 一级菜单名称 + */ + private String level1ResourceName; + + /** + * 一级菜单Code + */ + private String level1ResourceCode; + + /** + * 二级菜单名 + */ + private String level2ResourceName; + + /** + * 二级菜单Code + */ + private String level2ResourceCode; + + /** + * 二级菜单对应操作列表 + */ + private List operateList; + + /** + * 排序值 + */ + private Integer sort; + + + public static RolePermissionResourceEnum ofLevel1Code(String level1Code){ + return Stream.of(RolePermissionResourceEnum.values()).filter(v ->v.getLevel1ResourceCode().equals(level1Code)).findFirst().orElse(null); + } + public static List ofAll(){ + Map> level1CodeMap = Stream.of(RolePermissionResourceEnum.values()) + .collect(Collectors.groupingBy(RolePermissionResourceEnum::getLevel1ResourceCode)); + List result = Lists.newArrayList(); + //组装Level1 + level1CodeMap.keySet().forEach(key ->{ + RolePermissionResourceEnum level1Resource = ofLevel1Code(key); + RolePermission1VO rolePermissionVO = new RolePermission1VO(); + rolePermissionVO.setCode(level1Resource.level1ResourceCode); + rolePermissionVO.setSelect(0); + rolePermissionVO.setSort(level1Resource.sort); + rolePermissionVO.setResource(level1Resource.getLevel1ResourceName()); + List permission2VoList = Lists.newArrayList(); + rolePermissionVO.setLevel2ResourceList(permission2VoList); + result.add(rolePermissionVO); + + //组装Level2 + List level2ResourceList = level1CodeMap.get(key); + if(CollectionUtils.isEmpty(level2ResourceList)){ + return; + } + level2ResourceList.forEach(level2 ->{ + if(StringUtils.isEmpty(level2.level2ResourceCode)){ + return; + } + RolePermission2VO rolePermission2VO = new RolePermission2VO(); + rolePermission2VO.setCode(level2.level2ResourceCode); + rolePermission2VO.setSelect(0); + rolePermission2VO.setSort(level2.sort); + rolePermission2VO.setResource(level2.getLevel2ResourceName()); + List operationList = Lists.newArrayList(); + rolePermission2VO.setOperationList(operationList); + permission2VoList.add(rolePermission2VO); + + if(CollectionUtils.isEmpty(level2.operateList)){ + return; + } + level2.operateList.forEach(operate ->{ + RolePermissionOperationEnum operationEnum = RolePermissionOperationEnum.valueOf(operate); + RolePermission2OperationVO operationVO = RolePermission2OperationVO.builder() + .code(operate) + .resource(operationEnum.getDesc()) + .select(0) + .sort(operationEnum.getSort()).build(); + operationList.add(operationVO); + }); + Collections.sort(operationList, Comparator.comparing(RolePermission2OperationVO::getSort)); + }); + Collections.sort(permission2VoList, Comparator.comparing(RolePermission2VO::getSort)); + }); + Collections.sort(result, Comparator.comparing(RolePermission1VO::getSort)); + return result; + } +} diff --git a/src/main/java/com/mixi/common/httpdata/token/TokenApis.java b/src/main/java/com/mixi/common/httpdata/token/TokenApis.java new file mode 100644 index 0000000..b5b8f99 --- /dev/null +++ b/src/main/java/com/mixi/common/httpdata/token/TokenApis.java @@ -0,0 +1,33 @@ +package com.mixi.common.httpdata.token; + +public enum TokenApis { + /** + * token + */ + GET_TOKEN("POST", "/api/openApi/v2/Weixin/QrCodeLoginCheck?session="), + GENERATE_USER("POST", "/api/openApi/v2/Welink/TopicGetjson"); + + private String method; + private String url; + + TokenApis(String method, String url) { + this.method = method; + this.url = url; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} diff --git a/src/main/java/com/mixi/common/httpdata/token/TokenQuery.java b/src/main/java/com/mixi/common/httpdata/token/TokenQuery.java new file mode 100644 index 0000000..100ddd2 --- /dev/null +++ b/src/main/java/com/mixi/common/httpdata/token/TokenQuery.java @@ -0,0 +1,41 @@ +package com.mixi.common.httpdata.token; + +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpResponse; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class TokenQuery { + + private static final String GET_TOKEN_DOMAIN = "https://www.szsige.com"; + private static final String GENERATE_USER_DOMAIN = "https://www.szsige.com"; + + public static JSONObject getToken(String session) { + String url = GET_TOKEN_DOMAIN + TokenApis.GET_TOKEN.getUrl()+ session; + log.info("获取用户token接口请求url:" + url); + HttpResponse httpResponse = HttpUtil.createPost(url).execute(); + log.info("获取用户token接口响应:" + httpResponse); + if(httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())){ + return JSONObject.parseObject(httpResponse.body()); + } + return null; + } + public static JSONObject generateUser(Map param,String token) { + HttpResponse httpResponse = HttpUtil.createPost(GENERATE_USER_DOMAIN + TokenApis.GENERATE_USER.getUrl()) + .body(JSONObject.toJSONString(param!=null?param:new HashMap<>())) + .header("Authorization", "Bearer "+token) + .header("X-Promiss", "9672233956") + .execute(); + log.info("生成用户信息接口响应:" + httpResponse); + if(httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())){ + return JSONObject.parseObject(httpResponse.body()); + } + return null; + } + +} diff --git a/src/main/java/com/mixi/common/response/PageBaseResponse.java b/src/main/java/com/mixi/common/response/PageBaseResponse.java new file mode 100644 index 0000000..45ab5ee --- /dev/null +++ b/src/main/java/com/mixi/common/response/PageBaseResponse.java @@ -0,0 +1,45 @@ +package com.mixi.common.response; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @ClassName PageResponse + * @Description 分页响应 + * @Author dwjian + * @Date 2020/1/13 0:26 + */ +@Data +@NoArgsConstructor +@ApiModel("分页响应结果") +public class PageBaseResponse{ + @ApiModelProperty("页码") + private long page; + @ApiModelProperty("每页数量") + private long size; + @ApiModelProperty("总页数") + private long pages; + @ApiModelProperty("总条数") + private long total; + @ApiModelProperty("结果集") + private List content; + + + + public PageBaseResponse(List list, long page, long size, long total, long pages) { + this.page = page; + this.size = size; + this.total = total; + this.pages = pages; + this.content = list; + } + + public static com.mixi.common.response.PageBaseResponse success(IPage page){ + return new com.mixi.common.response.PageBaseResponse<>(page.getRecords() , page.getCurrent(), page.getSize(), page.getTotal(), page.getPages()); + } +} diff --git a/src/main/java/com/mixi/common/response/PageResponse.java b/src/main/java/com/mixi/common/response/PageResponse.java new file mode 100644 index 0000000..17dd102 --- /dev/null +++ b/src/main/java/com/mixi/common/response/PageResponse.java @@ -0,0 +1,46 @@ +package com.mixi.common.response; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @ClassName PageResponse + * @Description 分页响应 + * @Author dwjian + * @Date 2020/1/13 0:26 + */ +@Data +@NoArgsConstructor +@ApiModel("分页响应结果") +public class PageResponse extends Response> { + @ApiModelProperty("页码") + private long page; + @ApiModelProperty("每页数量") + private long size; + @ApiModelProperty("总页数") + private long pages; + @ApiModelProperty("总条数") + private long total; + + public PageResponse(Response> response, long page, long size, long total, long pages) { + if(response != null) { + this.setData(response.getData()); + this.setErrCode(response.getErrCode()); + this.setErrMsg(response.getErrMsg()); + } + this.page = page; + this.size = size; + this.total = total; + this.pages = pages; + } + + public static PageResponse success(IPage page){ + Response> response = success(page.getRecords()); + return new PageResponse<>(response , page.getCurrent(), page.getSize(), page.getTotal(), page.getPages()); + } +} diff --git a/src/main/java/com/mixi/common/response/Response.java b/src/main/java/com/mixi/common/response/Response.java new file mode 100644 index 0000000..0e44a23 --- /dev/null +++ b/src/main/java/com/mixi/common/response/Response.java @@ -0,0 +1,96 @@ +package com.mixi.common.response; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @ClassName Response + * @Description success代表响应成功 fail代表主动响应失败 error代表系统异常 + * @Author dwjian + * @Date 2019/9/8 21:48 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("响应结果") +public class Response implements Serializable { + + @ApiModelProperty("响应状态码 0:成功 -1:失败") + private int errCode; + @ApiModelProperty("提示消息") + private String errMsg; + @ApiModelProperty("数据结果") + private T data; + + public static Response success(){ + return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null); + } + + public static Response success(String msg){ + return success(ResultEnum.SUCCESS.getCode(), msg, null); + } + + public static Response success(T data){ + return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data); + } + public static Response successData(T data){ + return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data); + } + + public static Response success(int code, T data){ + return success(code, ResultEnum.SUCCESS.getMsg(), data); + } + + public static Response success(int code, String msg, T data){ + return getResponse(code, msg, data); + } + + + + public static Response fail(String msg) { + return fail(ResultEnum.FAIL.getCode(), msg); + } + + public static Response fail(T data) { + return fail(ResultEnum.FAIL.getCode(), ResultEnum.FAIL.getMsg(), data); + } + + public static Response fail(ResultEnum resultEnum) { + return fail(resultEnum.getCode(), resultEnum.getMsg(), null); + } + + public static Response fail(int code, String msg) { + return fail(code, msg, null); + } + + public static Response fail(int code, String msg, T data) { + return getResponse(code, msg, data); + } + + public static Response error(String msg) { + return error(ResultEnum.ERROR.getCode(), msg); + } + + public static Response error(T data) { + return error(ResultEnum.ERROR.getCode(), ResultEnum.ERROR.getMsg(), data); + } + + public static Response error(int code, String msg) { + return error(code, msg, null); + } + + public static Response error(int code, String msg, T data) { + return getResponse(code, msg, data); + } + + private static Response getResponse(int code, String msg, T data){ + return new Response<>(code, msg, data); + } + + +} diff --git a/src/main/java/com/mixi/common/response/ResultEnum.java b/src/main/java/com/mixi/common/response/ResultEnum.java new file mode 100644 index 0000000..b916519 --- /dev/null +++ b/src/main/java/com/mixi/common/response/ResultEnum.java @@ -0,0 +1,55 @@ +package com.mixi.common.response; + +/** + * @ClassName ResultEnum + * @Description 响应结果枚举 + * @Author dwjian + * @Date 2019/9/8 21:58 + */ +public enum ResultEnum { + + SUCCESS(true, 0, "SUCCESS"), + FAIL(false, -1, "FAIL"), + ERROR(false, -1, "系统异常"), + PARAMETER_ERROR(false, -2, "参数异常"), + + NO_LOGIN(false,-100,"用户未登录"), + NO_PERMISSION(false,-200,"无权限访问"), + ACCOUNT_LOCK(false,-300,"账号已冻结"); + + private int code; + private String msg; + private boolean isOK; + + + + ResultEnum(boolean isOK, int code, String msg){ + this.isOK = isOK; + this.code = code; + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public boolean isOK() { + return isOK; + } + + public void setOK(boolean OK) { + isOK = OK; + } +} diff --git a/src/main/java/com/mixi/common/security/UserAuthAccessDeniedHandler.java b/src/main/java/com/mixi/common/security/UserAuthAccessDeniedHandler.java new file mode 100644 index 0000000..aeaa4b4 --- /dev/null +++ b/src/main/java/com/mixi/common/security/UserAuthAccessDeniedHandler.java @@ -0,0 +1,27 @@ +package com.mixi.common.security; + +import com.mixi.common.response.Response; +import com.mixi.common.response.ResultEnum; +import com.mixi.common.utils.JSONResponseUtils; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @ClassName UserAuthAccessDeniedHandler + * @Description 无权限处理类 + * @Author dwjian + * @Date 2020/7/9 20:30 + */ +@Component +public class UserAuthAccessDeniedHandler implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException exception) throws IOException { + Response response = Response.error(ResultEnum.NO_PERMISSION.getCode(), ResultEnum.NO_PERMISSION.getMsg()); + JSONResponseUtils.build(httpServletResponse, response); + } +} diff --git a/src/main/java/com/mixi/common/security/UserAuthenticationEntryPointHandler.java b/src/main/java/com/mixi/common/security/UserAuthenticationEntryPointHandler.java new file mode 100644 index 0000000..d92ca06 --- /dev/null +++ b/src/main/java/com/mixi/common/security/UserAuthenticationEntryPointHandler.java @@ -0,0 +1,29 @@ +package com.mixi.common.security; + +import com.mixi.common.response.Response; +import com.mixi.common.response.ResultEnum; +import com.mixi.common.utils.JSONResponseUtils; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @ClassName UserAuthenticationEntryPointHandler + * @Description 未登录处理类 + * @Author dwjian + * @Date 2020/7/9 20:13 + */ +@Component +public class UserAuthenticationEntryPointHandler implements AuthenticationEntryPoint { + @Override + public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { + Response response = Response.error(ResultEnum.NO_LOGIN.getCode(), ResultEnum.NO_LOGIN.getMsg()); + httpServletResponse.setStatus(401); + JSONResponseUtils.build(httpServletResponse, response); + } +} diff --git a/src/main/java/com/mixi/common/security/UserAuthenticationManager.java b/src/main/java/com/mixi/common/security/UserAuthenticationManager.java new file mode 100644 index 0000000..ec22457 --- /dev/null +++ b/src/main/java/com/mixi/common/security/UserAuthenticationManager.java @@ -0,0 +1,25 @@ +package com.mixi.common.security; + +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * @author: dangweijian + * @description: 认证管理器 + * @create: 2020-07-10 15:58 + **/ +@Component +public class UserAuthenticationManager implements AuthenticationManager { + + @Resource + private UserAuthenticationProvider userAuthenticationProvider; + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + return userAuthenticationProvider.authenticate(authentication); + } +} diff --git a/src/main/java/com/mixi/common/security/UserAuthenticationProvider.java b/src/main/java/com/mixi/common/security/UserAuthenticationProvider.java new file mode 100644 index 0000000..672cfda --- /dev/null +++ b/src/main/java/com/mixi/common/security/UserAuthenticationProvider.java @@ -0,0 +1,59 @@ +package com.mixi.common.security; + +import com.mixi.common.config.RsaProperties; +import com.mixi.common.utils.RsaDecryptUtils; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.stereotype.Component; + +/** + * @author: dangweijian + * @description: 登录校验处理类 + * @create: 2020-07-09 14:39 + **/ +@Component +public class UserAuthenticationProvider implements AuthenticationProvider { + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + String userName = (String) authentication.getPrincipal(); + String password = (String) authentication.getCredentials(); + try { + password = RsaDecryptUtils.decrypt(password, RsaProperties.privateKey); + } catch (Exception e) { + throw new BadCredentialsException("用户名或密码错误"); + } +// User user = userService.getByUsername(userName); +// if (user == null) { +// throw new UsernameNotFoundException("用户名或密码错误"); +// } +// //账号已冻结 +// if(user.getStatus() == 1){ +// throw new LockedException("账号已冻结"); +// } +// if(!passwordEncoder.matches(password, user.getPassword())){ +// throw new BadCredentialsException("用户名或密码错误"); +// } +// //超级管理员 +// Set authorities = new HashSet<>(); +// if(user.getIsAdmin()) { +// authorities.add(new SimpleGrantedAuthority("admin")); +// return new UsernamePasswordAuthenticationToken(user, password, authorities); +// }else { +// List userMenus = menuService.getRoleMenusByUserId(user.getId(), null); +// if(CollUtil.isNotEmpty(userMenus)){ +// authorities.addAll(userMenus.stream().map(RoleMenuDto::getPermission).filter(StringUtils::isNotEmpty).map(SimpleGrantedAuthority::new).collect(Collectors.toSet())); +// } +// return new UsernamePasswordAuthenticationToken(user, password, authorities); +// } + return null; + } + + @Override + public boolean supports(Class aClass) { + return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass); + } +} diff --git a/src/main/java/com/mixi/common/security/UserLoginFailureHandler.java b/src/main/java/com/mixi/common/security/UserLoginFailureHandler.java new file mode 100644 index 0000000..1aeda4f --- /dev/null +++ b/src/main/java/com/mixi/common/security/UserLoginFailureHandler.java @@ -0,0 +1,48 @@ +package com.mixi.common.security; + +import com.mixi.common.response.Response; +import com.mixi.common.response.ResultEnum; +import com.mixi.common.utils.JSONResponseUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.*; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; +import org.springframework.stereotype.Component; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @ClassName UserLoginFailureHandler + * @Description 登录失败处理类 + * @Author dwjian + * @Date 2020/7/9 20:17 + */ +@Slf4j +@Component +public class UserLoginFailureHandler implements AuthenticationFailureHandler { + @Override + public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { + Response response; + if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) { + response = Response.fail(e.getMessage()); + } else if (e instanceof LockedException) { + response = Response.fail(ResultEnum.ACCOUNT_LOCK); + } else if (e instanceof CredentialsExpiredException) { + response = Response.fail("证书过期,请联系管理员!"); + } else if (e instanceof AccountExpiredException) { + response = Response.fail("账户过期,请联系管理员!"); + } else if (e instanceof DisabledException) { + response = Response.fail("账户被禁用,请联系管理员!"); + } else if (e instanceof AuthenticationServiceException) { + response = Response.fail(e.getMessage()); + } else { + log.error("登录失败:", e); + response = Response.fail("登录失败!"); + } + JSONResponseUtils.build(httpServletResponse,response); + } +} diff --git a/src/main/java/com/mixi/common/security/UserLoginSuccessHandler.java b/src/main/java/com/mixi/common/security/UserLoginSuccessHandler.java new file mode 100644 index 0000000..11c425a --- /dev/null +++ b/src/main/java/com/mixi/common/security/UserLoginSuccessHandler.java @@ -0,0 +1,51 @@ +package com.mixi.common.security; + +import com.mixi.common.response.Response; +import com.mixi.common.response.ResultEnum; +import com.mixi.common.security.jwt.JWTTokenHelper; +import com.mixi.common.utils.JSONResponseUtils; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * @author: dangweijian + * @description: 登录成功处理类 + * @create: 2020-07-09 14:58 + **/ +@Component +public class UserLoginSuccessHandler implements AuthenticationSuccessHandler { + + @Resource + private JWTTokenHelper jwtTokenHelper; + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { +// User user = (User) authentication.getPrincipal(); +// AuthPrincipalVo principal = new AuthPrincipalVo(); +// BeanUtils.copyProperties(user, principal); +// // 获取用户角色 +// List userRoles = roleService.getUserRoles(user.getId(), 0); +// principal.setRoles(userRoles); +// // 获取角色部门 +// if(CollUtil.isNotEmpty(userRoles)){ +// principal.setDepts(deptService.getDeptByRoleIds(userRoles.stream().map(UserRoleDto::getRoleId).collect(Collectors.toList()))); +// } +// // 用户角色权限 +// List authorities = new ArrayList<>(authentication.getAuthorities()).stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); +// principal.setAuthorities(authorities); +// AuthVo authVo = new AuthVo(); +// authVo.setAuthorities(authorities); +// authVo.setToken(jwtTokenHelper.createToken(principal)); +// authVo.setPrincipal(principal); +// user.setLastLoginTime(new Date()); +// userService.updateById(user); + JSONResponseUtils.build(response, Response.success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null)); + } +} diff --git a/src/main/java/com/mixi/common/security/UserPermissionEvaluator.java b/src/main/java/com/mixi/common/security/UserPermissionEvaluator.java new file mode 100644 index 0000000..b84e930 --- /dev/null +++ b/src/main/java/com/mixi/common/security/UserPermissionEvaluator.java @@ -0,0 +1,34 @@ +package com.mixi.common.security; + +import org.springframework.security.access.PermissionEvaluator; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import java.io.Serializable; + +/** + * @ClassName UserPermissionEvaluator + * @Description 权限校验处理器 + * @Author dwjian + * @Date 2020/7/12 10:16 + */ +@Component +public class UserPermissionEvaluator implements PermissionEvaluator { + + @Override + public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) { + System.out.println(authentication); + System.out.println(targetUrl); + System.out.println(permission); + return false; + } + + @Override + public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { + System.out.println(authentication); + System.out.println(targetId); + System.out.println(targetType); + System.out.println(permission); + return false; + } +} diff --git a/src/main/java/com/mixi/common/security/config/SecurityConfig.java b/src/main/java/com/mixi/common/security/config/SecurityConfig.java new file mode 100644 index 0000000..b990744 --- /dev/null +++ b/src/main/java/com/mixi/common/security/config/SecurityConfig.java @@ -0,0 +1,79 @@ +package com.mixi.common.security.config; + +import com.mixi.common.security.*; +import com.mixi.common.security.*; +import com.mixi.common.security.filter.AuthenticationFilter; +import com.mixi.common.security.filter.UserAuthenticationProcessingFilter; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; + +import javax.annotation.Resource; + +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +@EnableConfigurationProperties(SecurityProperties.class) +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Resource + private SecurityProperties securityProperties; + @Resource + private UserLoginSuccessHandler userLoginSuccessHandler; + @Resource + private UserLoginFailureHandler userLoginFailureHandler; + @Resource + private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler; + @Resource + private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler; + @Resource + private UserAuthenticationManager userAuthenticationManager; + @Resource + private UserAuthenticationProcessingFilter userAuthenticationProcessingFilter; + @Resource + private AuthenticationFilter authenticationFilter; + @Resource + private UserPermissionEvaluator userPermissionEvaluator; + + + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return this.userAuthenticationManager; + } + + @Override + protected void configure(HttpSecurity httpSecurity) throws Exception { + httpSecurity.cors().disable()//禁用 CSRF + .authorizeRequests()//认证请求 + .antMatchers(securityProperties.getIgnorePaths()).permitAll()//忽略的请求 + .anyRequest().authenticated()//其余所有的请求都需要认证 + .and().headers().frameOptions().disable()// 防止iframe 造成跨域 + .and().exceptionHandling().authenticationEntryPoint(userAuthenticationEntryPointHandler)//未登录请求处理 + .accessDeniedHandler(userAuthAccessDeniedHandler)//无权限访问处理类 (此配置可以忽略,全局异常会先于Security框架处理异常,全局异常已特殊处理) + .and().formLogin().loginProcessingUrl(securityProperties.getAuthApi())//指定认证接口 + .successHandler(userLoginSuccessHandler)//登录成功处理器 + .failureHandler(userLoginFailureHandler)//登录失败处理器 + .and().cors().and().csrf().disable();//允许跨域 + //自定义过滤器在登录时认证用户名、密码 + httpSecurity.addFilterAt(userAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(authenticationFilter, BasicAuthenticationFilter.class); + //不创建session会话 + httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); + //取消头缓存控制 + httpSecurity.headers().cacheControl(); + } + + @Bean + public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() { + DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler(); + handler.setPermissionEvaluator(userPermissionEvaluator); + return handler; + } +} diff --git a/src/main/java/com/mixi/common/security/config/SecurityProperties.java b/src/main/java/com/mixi/common/security/config/SecurityProperties.java new file mode 100644 index 0000000..d8959ad --- /dev/null +++ b/src/main/java/com/mixi/common/security/config/SecurityProperties.java @@ -0,0 +1,26 @@ +package com.mixi.common.security.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author: dangweijian + * @description: JWT配置类 + * @create: 2020-07-09 09:38 + **/ +@Data +@ConfigurationProperties(prefix = "spring.security") +public class SecurityProperties { + + private String jwtSecret; + + private String jwtTokenHeader; + + private String jwtTokenPrefix; + + private long jwtExpiration; + + private String[] ignorePaths; + + private String authApi; +} diff --git a/src/main/java/com/mixi/common/security/filter/AuthenticationFilter.java b/src/main/java/com/mixi/common/security/filter/AuthenticationFilter.java new file mode 100644 index 0000000..3d5632c --- /dev/null +++ b/src/main/java/com/mixi/common/security/filter/AuthenticationFilter.java @@ -0,0 +1,121 @@ +package com.mixi.common.security.filter; + +import cn.hutool.core.util.StrUtil; +import com.mixi.common.context.UserContext; +import com.mixi.common.security.config.SecurityProperties; +import com.mixi.common.security.jwt.JWTTokenHelper; +import com.mixi.common.utils.LocalCacheUtils; +import com.mixi.common.utils.MultiReadHttpServletRequest; +import com.mixi.common.utils.MultiReadHttpServletResponse; +import com.mixi.model.vo.AuthPrincipalVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; +import org.springframework.lang.NonNull; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.StopWatch; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.annotation.Resource; +import javax.security.sasl.AuthenticationException; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +/** + * @author: dangweijian + * @description: 认证拦截器 + * @create: 2020-07-10 16:50 + **/ +@Slf4j +@Configuration +public class AuthenticationFilter extends OncePerRequestFilter { + + @Resource + private JWTTokenHelper jwtTokenHelper; + @Resource + private SecurityProperties properties; + + private static final List FILTER_URL = + Arrays.asList("/favicon.ico","/doc.html","api/account/login","api/account/resetPwd", + "/webjars/","/swagger-resources","/v2/api-docs", + "/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId","/api/element/initDefaultSysFile" + ,"api/app/account/login","api/app/account/resetPwd"); + + @Override + protected void doFilterInternal(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) throws ServletException, IOException { + String requestURI = httpServletRequest.getRequestURI(); + + if(calculateUrl(requestURI)){ + StopWatch stopWatch = new StopWatch(); + HttpServletRequest wrappedRequest = httpServletRequest; + HttpServletResponse wrappedResponse = httpServletResponse; + try{ + stopWatch.start(); + if ((httpServletRequest.getContentType() == null && httpServletRequest.getContentLength() > 0) || (httpServletRequest.getContentType() != null && !httpServletRequest.getContentType().contains("application/json"))) { + extracted(wrappedRequest); + filterChain.doFilter(wrappedRequest, wrappedResponse); + }else { + wrappedRequest = new MultiReadHttpServletRequest(httpServletRequest); + wrappedResponse = new MultiReadHttpServletResponse(httpServletResponse); + extracted(wrappedRequest); + filterChain.doFilter(wrappedRequest, wrappedResponse); + } + } catch (Exception e) { + SecurityContextHolder.clearContext(); + throw e; + } finally { + stopWatch.stop(); + } + }else { + filterChain.doFilter(httpServletRequest, httpServletResponse); + } + } + private Boolean calculateUrl(String requestURI ){ + String filterUrl = FILTER_URL.stream().filter(url ->requestURI.contains(url)).findFirst().orElse(null); + return null == filterUrl ? Boolean.TRUE :Boolean.FALSE; + } + private void extracted(HttpServletRequest request) throws AuthenticationException { + String jwtToken = request.getHeader(properties.getJwtTokenHeader()); + log.debug("后台检查令牌:{}", jwtToken); + + if (StrUtil.isBlank(jwtToken)) { + throw new RuntimeException("请传入token!"); + } + // 检查token + boolean validate = jwtTokenHelper.validateToken(jwtToken); + if(validate){ + AuthPrincipalVo principal = jwtTokenHelper.parserToUser(jwtToken); + if (principal == null) { + throw new RuntimeException("TOKEN已过期,请重新登录!"); + } + //先清空当前线程变量,防止上一个线程遗留 + UserContext.delete(); + //存取用户信息到缓存 + UserContext.setUserHolder(principal); + //校验token + String cacheToken = LocalCacheUtils.getTokenCache(String.valueOf(principal.getId())); + if(StringUtils.isEmpty(cacheToken)){ + //兼容app端 + cacheToken = LocalCacheUtils.getTokenCache("APP_"+principal.getId()); + } + if(jwtToken.equals("Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIxIiwic3ViIjoie1wiaWRcIjoxLFwidXNlcm5hbWVcIjpcInlhbmdsZWlcIn0iLCJpYXQiOjE2NzgyNjQwNzMsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2ODY5MDQwNzN9.wHDZWC90sXxom16QUW9MoYXhSr00FXEkRMy6DtsCATCa68PCgIORRXfjoVH9QXPoSVLNYkGKMjG3FR1MjAQ7Pg")){ + //写死 暂时放行 + return; + } + if(StringUtils.isEmpty(cacheToken)){ + throw new RuntimeException("TOKEN已过期,请重新登录!"); + } + //按照同一用户原则,不比较token了 app端和web端用一个做 +// if(!cacheToken.equals(jwtToken) ){ +// throw new RuntimeException("TOKEN已过期,请重新登录!"); +// } +// UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(null, null); +// SecurityContextHolder.getContext().setAuthentication(authentication); + } + } +} diff --git a/src/main/java/com/mixi/common/security/filter/UserAuthenticationProcessingFilter.java b/src/main/java/com/mixi/common/security/filter/UserAuthenticationProcessingFilter.java new file mode 100644 index 0000000..793d2aa --- /dev/null +++ b/src/main/java/com/mixi/common/security/filter/UserAuthenticationProcessingFilter.java @@ -0,0 +1,69 @@ +package com.mixi.common.security.filter; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.mixi.common.security.UserAuthenticationManager; +import com.mixi.common.security.UserLoginFailureHandler; +import com.mixi.common.security.UserLoginSuccessHandler; +import com.mixi.common.security.config.SecurityProperties; +import com.mixi.common.utils.MultiReadHttpServletRequest; +import com.mixi.common.utils.RedisCacheUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * @author: dangweijian + * @description: 用户认证过滤器 + * @create: 2020-07-10 15:58 + **/ +@Slf4j +@Component +public class UserAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter { + + /** + * @param securityProperties 配置(从配置中读取登录url) + * @param authenticationManager 认证管理器 + * @param adminAuthenticationSuccessHandler 认证成功处理器 + * @param adminAuthenticationFailureHandler 认证失败处理器 + */ + public UserAuthenticationProcessingFilter(SecurityProperties securityProperties, UserAuthenticationManager authenticationManager, UserLoginSuccessHandler adminAuthenticationSuccessHandler, UserLoginFailureHandler adminAuthenticationFailureHandler) { + super(new AntPathRequestMatcher(securityProperties.getAuthApi(), HttpMethod.POST.name())); + this.setAuthenticationManager(authenticationManager); + this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler); + this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { + if (request.getContentType() == null || !request.getContentType().contains("application/json")) { + throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType()); + } + UsernamePasswordAuthenticationToken authRequest; + try { + MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request); + // 将前端传递的数据转换成jsonBean数据格式 + JSONObject jsonObject = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest)); + String code = jsonObject.getString("code"); + String uuid = jsonObject.getString("uuid"); + if (StrUtil.isEmpty(code) || StrUtil.isEmpty(uuid) || !code.equals(RedisCacheUtils.get("code-key-" + uuid, String.class))) { + throw new AuthenticationServiceException("验证码错误"); + } + RedisCacheUtils.delete("code-key-" + uuid); + authRequest = new UsernamePasswordAuthenticationToken(jsonObject.get("username"), jsonObject.get("password"), null); + authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest)); + } catch (Exception e) { + throw new AuthenticationServiceException(e.getMessage()); + } + return this.getAuthenticationManager().authenticate(authRequest); + } +} diff --git a/src/main/java/com/mixi/common/security/jwt/JWTTokenHelper.java b/src/main/java/com/mixi/common/security/jwt/JWTTokenHelper.java new file mode 100644 index 0000000..d478667 --- /dev/null +++ b/src/main/java/com/mixi/common/security/jwt/JWTTokenHelper.java @@ -0,0 +1,68 @@ +package com.mixi.common.security.jwt; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.mixi.common.security.config.SecurityProperties; +import com.mixi.model.vo.AuthPrincipalVo; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; + +/** + * @author: dangweijian + * @description: JWT工具 + * @create: 2020-07-09 09:27 + **/ +@Slf4j +@Component +public class JWTTokenHelper { + + @Resource + private SecurityProperties securityProperties; + + private static final String ISSUER = "DWJ"; + private static final String AUTHORITIES = "authorities"; + + public String createToken(AuthPrincipalVo principal){ + String token = Jwts.builder() + .setId(String.valueOf(principal.getId())) + .setSubject(JSONObject.toJSONString(principal)) + .setIssuedAt(new Date()) + .setIssuer(ISSUER) + .claim(AUTHORITIES, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限 + .setExpiration(new Date(System.currentTimeMillis() + securityProperties.getJwtExpiration())) + .signWith(SignatureAlgorithm.HS512, securityProperties.getJwtSecret()) + .compact(); + token = securityProperties.getJwtTokenPrefix() + token; + return token; + } + + public boolean validateToken(String token){ + Claims claims = parser(token); + if (MapUtil.isEmpty(claims)){ + return false; + } + return true; + } + + public AuthPrincipalVo parserToUser(String token){ + String subject = parser(token).getSubject(); + if(StrUtil.isNotEmpty(subject)){ + return JSONObject.parseObject(subject, AuthPrincipalVo.class); + } + return null; + } + + public Claims parser(String token) { + token = token.replaceAll(securityProperties.getJwtTokenPrefix(),""); + return Jwts.parser().setSigningKey(securityProperties.getJwtSecret()).parseClaimsJws(token).getBody(); + } +} diff --git a/src/main/java/com/mixi/common/tasks/MiTuExportScheduledTask.java b/src/main/java/com/mixi/common/tasks/MiTuExportScheduledTask.java new file mode 100644 index 0000000..db2bc32 --- /dev/null +++ b/src/main/java/com/mixi/common/tasks/MiTuExportScheduledTask.java @@ -0,0 +1,1440 @@ +package com.mixi.common.tasks; + +import com.mixi.common.tasks.mituExportEntity.*; +import com.mixi.mapper.MiTuExportMapper; +import com.mixi.mapper.entity.MiTuExport; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Retryable; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.sql.*; +import java.text.SimpleDateFormat; +import java.time.DayOfWeek; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +@Component +public class MiTuExportScheduledTask { + + static final String JDBC_DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; + static final String DB_URL = "jdbc:sqlserver://118.142.0.178:1550;databaseName=Hayman_prod"; + + // 数据库凭据 + static final String USER = "user01"; + static final String PASS = "haySIS-0522"; + + @Resource + private MiTuExportMapper miTuExportMapper; + + @PostConstruct + public void executeWeeklyHeavyStockReport() { +// customerPurchaseReport(); +// NewJoinVIPReport(); +// weeklySellThrReport(); +// WeeklyHeavyStockReport(); +// QuarterlyProductGroupingReport(); + } + + /** + * Customer purchase report + */ + @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000)) +// @Scheduled(cron = "0 0 22 L * ?") + public void customerPurchaseReport() { + MiTuExport miTuExport = createMiTuExport("Customer purchase report", "month"); + try { + List transactionData = retrieveTransactionData(); + List userMembers = transactionData.stream().map(TransactionData::getUserMember).collect(Collectors.toList()); + List customerData = retrieveCustomerData(userMembers); + updateCustomerDataWithTransactionData(customerData, transactionData); + String filePath = "C:\\Users\\10233\\Desktop\\MiTuExport\\"+miTuExport.getExportName()+".xlsx"; + exportToExcelCustomerPurchaseReport(customerData, filePath); + miTuExport.setStatus(1); + } catch (Exception e) { + miTuExport.setStatus(0); + e.printStackTrace(); + } finally { + miTuExportMapper.insert(miTuExport); + System.out.println("接口执行完成!"); + } + } + + private MiTuExport createMiTuExport(String fileName, String period) { + LocalDateTime currentDateTime = LocalDateTime.now(); + LocalDateTime startTime; + LocalDateTime endTime; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String exportName; + + switch (period) { + case "week": + startTime = currentDateTime.with(DayOfWeek.MONDAY).with(LocalTime.MIN); + endTime = currentDateTime.with(DayOfWeek.SUNDAY).with(LocalTime.MAX); + exportName = fileName + "_Week_" + currentDateTime.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + break; + case "month": + startTime = currentDateTime.withDayOfMonth(1).with(LocalTime.MIN); + endTime = currentDateTime.withDayOfMonth(currentDateTime.toLocalDate().lengthOfMonth()).with(LocalTime.MAX); + exportName = fileName + "_Month_" + currentDateTime.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + break; + case "year": + startTime = currentDateTime.withDayOfYear(1).with(LocalTime.MIN); + endTime = currentDateTime.withDayOfYear(currentDateTime.toLocalDate().lengthOfYear()).with(LocalTime.MAX); + exportName = fileName + "_Year_" + currentDateTime.format(DateTimeFormatter.ofPattern("yyyyMMdd")); + break; + default: + throw new IllegalArgumentException("Invalid period argument: " + period); + } + + String startOfPeriod = startTime.format(formatter); + String endOfPeriod = endTime.format(formatter); + + MiTuExport miTuExport = new MiTuExport(); + miTuExport.setExportName(exportName); + miTuExport.setSpan(period); + miTuExport.setCreateTime(LocalDateTime.now()); + miTuExport.setDataTime(startOfPeriod + " - " + endOfPeriod); + return miTuExport; + } + + + private void updateCustomerDataWithTransactionData(List customerDataList, List transactionDataList) { + for (TransactionData transactionDatum : transactionDataList) { + for (CustomerData customerDatum : customerDataList) { + if (customerDatum.getMbrCode().equals(transactionDatum.getUserMember())) { + customerDatum.setThisMonth(transactionDatum.getThisMonth()); + customerDatum.setMonth1(transactionDatum.getMonth1()); + customerDatum.setMonth2(transactionDatum.getMonth2()); + customerDatum.setMonth3(transactionDatum.getMonth3()); + customerDatum.setMonth4(transactionDatum.getMonth4()); + customerDatum.setMonth5(transactionDatum.getMonth5()); + customerDatum.setMonth6(transactionDatum.getMonth6()); + customerDatum.setMonth7(transactionDatum.getMonth7()); + customerDatum.setMonth8(transactionDatum.getMonth8()); + customerDatum.setMonth9(transactionDatum.getMonth9()); + customerDatum.setMonth10(transactionDatum.getMonth10()); + customerDatum.setMonth11(transactionDatum.getMonth11()); + customerDatum.setMonth12(transactionDatum.getMonth12()); + break; + } + } + } + } + + + /** + * New Join VIP report + */ + @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000)) +// @Scheduled(cron = "0 0 22 L * ?") + public void NewJoinVIPReport() { + MiTuExport miTuExport = createMiTuExport("New Join VIP report", "week"); + try { + List transactionNewCustomerList = getTransactionNewCustomerList(); + String filePath = "C:\\Users\\10233\\Desktop\\MiTuExport\\"+miTuExport.getExportName()+".xlsx"; + exportNewJoinVIPReport(transactionNewCustomerList, filePath); + miTuExport.setStatus(1); + } catch (Exception e) { + miTuExport.setStatus(0); + e.printStackTrace(); + } finally { + miTuExportMapper.insert(miTuExport); + System.out.println("接口执行完成!"); + } + } + + private static void exportNewJoinVIPReport(List transactionNewCustomerList, String filePathName) throws IOException { + File file = new File(filePathName); + boolean fileExists = file.exists(); + + // 如果文件不存在,则创建一个新的 Workbook + Workbook workbook = fileExists ? WorkbookFactory.create(file) : new XSSFWorkbook(); + + // 创建一个新的 Sheet 或获取现有的 Sheet + Sheet sheet = workbook.getSheet("Transaction New Customer"); + if (sheet == null) { + sheet = workbook.createSheet("Transaction New Customer"); + } + + // 创建标题行 + Row headerRow = sheet.getRow(0); + if (headerRow == null) { + headerRow = sheet.createRow(0); + } + + // 写入标题行 + headerRow.createCell(0).setCellValue("shCode"); + headerRow.createCell(1).setCellValue("userMember"); + headerRow.createCell(2).setCellValue("mbrName"); + headerRow.createCell(3).setCellValue("mbrMobile"); + headerRow.createCell(4).setCellValue("joinDate"); + headerRow.createCell(5).setCellValue("salesAmt"); + headerRow.createCell(6).setCellValue("vipGrade"); + headerRow.createCell(7).setCellValue("salesmanName"); + + // 写入数据 + int rowNum = sheet.getLastRowNum() + 1; + for (TransactionNewCustomer transactionNewCustomer : transactionNewCustomerList) { + Row row = sheet.createRow(rowNum++); + + row.createCell(0).setCellValue(transactionNewCustomer.getShCode()); + row.createCell(1).setCellValue(transactionNewCustomer.getUserMember()); + row.createCell(2).setCellValue(transactionNewCustomer.getMbrName()); + row.createCell(3).setCellValue(transactionNewCustomer.getMbrMobile()); + row.createCell(4).setCellValue(transactionNewCustomer.getJoinDate()); + row.createCell(5).setCellValue(transactionNewCustomer.getSalesAmt()); + row.createCell(6).setCellValue(transactionNewCustomer.getVipGrade()); + row.createCell(7).setCellValue(transactionNewCustomer.getSalesmanName()); + } + + // 将Workbook写入文件 + try (FileOutputStream outputStream = new FileOutputStream(file)) { + workbook.write(outputStream); + } + + System.out.println("Excel file has been created successfully!"); + } + + + /** + * Weekly Sell Through Report + */ + @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000)) +// @Scheduled(cron = "0 0 22 L * ?") + public void weeklySellThrReport() { + MiTuExport miTuExport = createMiTuExport("weeklySellThrReport", "week"); + try { + List transactionSummaryList = getTransactionSummaryList(); + String filePath = "C:\\Users\\10233\\Desktop\\MiTuExport\\"+miTuExport.getExportName()+".xlsx"; + exportWeeklySellThrReport(transactionSummaryList, filePath); + miTuExport.setStatus(1); + } catch (Exception e) { + miTuExport.setStatus(0); + e.printStackTrace(); + } finally { + miTuExportMapper.insert(miTuExport); + System.out.println("接口执行完成!"); + } + } + + private void exportWeeklySellThrReport(List transactionSummaryList, String weeklySellThrReportName) throws IOException { + File file = new File(weeklySellThrReportName); + boolean fileExists = file.exists(); + + // 如果文件不存在,则创建一个新的 Workbook + Workbook workbook = fileExists ? WorkbookFactory.create(file) : new XSSFWorkbook(); + + // 创建一个新的 Sheet 或获取现有的 Sheet + Sheet sheet = workbook.getSheet("Weekly Sell Through Report"); + if (sheet == null) { + sheet = workbook.createSheet("Weekly Sell Through Report"); + } + + // 写入标题行 + Row headerRow = sheet.getRow(0); + if (headerRow == null) { + headerRow = sheet.createRow(0); + } + headerRow.createCell(0).setCellValue("PLU_CODE"); + headerRow.createCell(1).setCellValue("ToShopDate"); + headerRow.createCell(2).setCellValue("SalesDay"); + headerRow.createCell(3).setCellValue("CATEGORY"); + headerRow.createCell(4).setCellValue("SUB_CAT"); + headerRow.createCell(5).setCellValue("ItemName"); + headerRow.createCell(6).setCellValue("PriceOriginal"); + headerRow.createCell(7).setCellValue("ToRetailQty"); + headerRow.createCell(8).setCellValue("TotalSaleNum"); + headerRow.createCell(9).setCellValue("MAS_count"); + headerRow.createCell(10).setCellValue("MEL_count"); + headerRow.createCell(11).setCellValue("MPC_count"); + headerRow.createCell(12).setCellValue("MPS_count"); + headerRow.createCell(13).setCellValue("MTF_count"); + headerRow.createCell(14).setCellValue("MWP_count"); + headerRow.createCell(15).setCellValue("MYO_count"); + headerRow.createCell(16).setCellValue("LwSalesQty"); + headerRow.createCell(17).setCellValue("RetailOnHand"); + headerRow.createCell(18).setCellValue("SalesRate"); + + // 写入数据 + int rowNum = sheet.getLastRowNum() + 1; + for (TransactionSummary summary : transactionSummaryList) { + Row row = sheet.createRow(rowNum++); + + row.createCell(0).setCellValue(summary.getPLU_CODE()); + if (summary.getToShopDate() != null) { + row.createCell(1).setCellValue(summary.getToShopDate().toString()); + }else { + row.createCell(1).setCellValue(""); + } + row.createCell(2).setCellValue(summary.getSalesDay()); + row.createCell(3).setCellValue(summary.getCATEGORY()); + row.createCell(4).setCellValue(summary.getSUB_CAT()); + row.createCell(5).setCellValue(summary.getItemName()); + row.createCell(6).setCellValue(summary.getPriceOriginal()); + row.createCell(7).setCellValue(summary.getToRetailQty()); + row.createCell(8).setCellValue(summary.getTotalSaleNum()); + row.createCell(9).setCellValue(summary.getMAS_count()); + row.createCell(10).setCellValue(summary.getMEL_count()); + row.createCell(11).setCellValue(summary.getMPC_count()); + row.createCell(12).setCellValue(summary.getMPS_count()); + row.createCell(13).setCellValue(summary.getMTF_count()); + row.createCell(14).setCellValue(summary.getMWP_count()); + row.createCell(15).setCellValue(summary.getMYO_count()); + row.createCell(16).setCellValue(summary.getLwSalesQty()); + row.createCell(17).setCellValue(summary.getRetailOnHand()); + row.createCell(18).setCellValue(summary.getSalesRate()); + } + + // 将Workbook写入文件 + try (FileOutputStream outputStream = new FileOutputStream(file)) { + workbook.write(outputStream); + } + + System.out.println("Excel file has been created successfully!"); + } + + + /** + * WeeklyHeavyStockReport + */ + @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000)) +// @Scheduled(cron = "0 0 22 L * ?") + public void WeeklyHeavyStockReport() { + MiTuExport miTuExport = createMiTuExport("WeeklyHeavyStockReport", "week"); + try { + List weeklyHeavyStockList = getWeeklyHeavyStockList(); + String filePath = "C:\\Users\\10233\\Desktop\\MiTuExport\\"+miTuExport.getExportName()+".xlsx"; + exportWeeklyHeavyStock(weeklyHeavyStockList, filePath); + miTuExport.setStatus(1); + } catch (Exception e) { + miTuExport.setStatus(0); + e.printStackTrace(); + } finally { + miTuExportMapper.insert(miTuExport); + System.out.println("接口执行完成!"); + } + } + + private static void exportWeeklyHeavyStock(List weeklyHeavyStockList, String weeklyHeavyStockReportName) { + // 创建工作簿 + Workbook workbook = new XSSFWorkbook(); + // 创建工作表 + Sheet sheet = workbook.createSheet("Weekly Heavy Stock Report"); + // 创建标题行 + Row headerRow = sheet.createRow(0); + headerRow.createCell(0).setCellValue("PLU_CODE"); + headerRow.createCell(1).setCellValue("item_name"); + headerRow.createCell(2).setCellValue("item_barcode"); + headerRow.createCell(3).setCellValue("cat"); + headerRow.createCell(4).setCellValue("sub_cat"); + headerRow.createCell(5).setCellValue("Col"); + headerRow.createCell(6).setCellValue("price_sales"); + headerRow.createCell(7).setCellValue("MAS"); + headerRow.createCell(8).setCellValue("MEL"); + headerRow.createCell(9).setCellValue("MPC"); + headerRow.createCell(10).setCellValue("MPS"); + headerRow.createCell(11).setCellValue("MTF"); + headerRow.createCell(12).setCellValue("MWP"); + headerRow.createCell(13).setCellValue("MYO"); + headerRow.createCell(14).setCellValue("MHZ"); + headerRow.createCell(15).setCellValue("MRT"); + headerRow.createCell(16).setCellValue("MBZ"); + headerRow.createCell(17).setCellValue("TLT"); + headerRow.createCell(18).setCellValue("subtotal"); + headerRow.createCell(19).setCellValue("G.TLT"); + + // 写入数据 + int rowNum = 1; + for (WeeklyHeavyStock weeklyHeavyStock : weeklyHeavyStockList) { + Row row = sheet.createRow(rowNum++); + row.createCell(0).setCellValue(weeklyHeavyStock.getPLU_CODE()); + row.createCell(1).setCellValue(weeklyHeavyStock.getItem_name()); + row.createCell(2).setCellValue(weeklyHeavyStock.getItem_barcode()); + row.createCell(3).setCellValue(weeklyHeavyStock.getCat()); + row.createCell(4).setCellValue(weeklyHeavyStock.getSub_cat()); + row.createCell(5).setCellValue(weeklyHeavyStock.getCol()); + row.createCell(6).setCellValue(weeklyHeavyStock.getPrice_sales()); + row.createCell(7).setCellValue(weeklyHeavyStock.getMAS()); + row.createCell(8).setCellValue(weeklyHeavyStock.getMEL()); + row.createCell(9).setCellValue(weeklyHeavyStock.getMPC()); + row.createCell(10).setCellValue(weeklyHeavyStock.getMPS()); + row.createCell(11).setCellValue(weeklyHeavyStock.getMTF()); + row.createCell(12).setCellValue(weeklyHeavyStock.getMWP()); + row.createCell(13).setCellValue(weeklyHeavyStock.getMYO()); + row.createCell(14).setCellValue(weeklyHeavyStock.getMHZ()); + row.createCell(15).setCellValue(weeklyHeavyStock.getMRT()); + row.createCell(16).setCellValue(weeklyHeavyStock.getMBZ()); + row.createCell(17).setCellValue(weeklyHeavyStock.getTLT()); + row.createCell(18).setCellValue(weeklyHeavyStock.getSubtotal()); + row.createCell(19).setCellValue(weeklyHeavyStock.getG_TLT()); + } + + // 将工作簿写入文件 + try (FileOutputStream outputStream = new FileOutputStream(weeklyHeavyStockReportName)) { + workbook.write(outputStream); + } catch (IOException e) { + e.printStackTrace(); + } + + System.out.println("Excel file has been created successfully!"); + } + + + /** + * Quarterly Product Grouping Report + */ + @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 1000)) +// @Scheduled(cron = "0 0 22 L * ?") + public void QuarterlyProductGroupingReport() { + MiTuExport miTuExport = createMiTuExport("Quarterly Product Grouping Report", "week"); + try { + List QuarterlyProductGroupingList = getQuarterlyProductGroupingList(); + String filePath = "C:\\Users\\10233\\Desktop\\MiTuExport\\"+miTuExport.getExportName()+".xlsx"; + exportQuarterlyProductGrouping(QuarterlyProductGroupingList, filePath); + miTuExport.setStatus(1); + } catch (Exception e) { + miTuExport.setStatus(0); + e.printStackTrace(); + } finally { + miTuExportMapper.insert(miTuExport); + System.out.println("接口执行完成!"); + } + } + + private static void exportQuarterlyProductGrouping(List weeklyHeavyStockList, String weeklyHeavyStockReportName) { + // 创建工作簿 + Workbook workbook = new XSSFWorkbook(); + // 创建工作表 + Sheet sheet = workbook.createSheet("Quarterly Product Grouping Report"); + // 创建标题行 + Row headerRow = sheet.createRow(0); + headerRow.createCell(0).setCellValue("PLU_CODE"); + headerRow.createCell(1).setCellValue("Col"); + headerRow.createCell(2).setCellValue("Size"); + headerRow.createCell(3).setCellValue("item_barcode"); + headerRow.createCell(4).setCellValue("item_name"); + headerRow.createCell(5).setCellValue("cat"); + headerRow.createCell(6).setCellValue("sub_cat"); + headerRow.createCell(7).setCellValue("price_sales"); + headerRow.createCell(8).setCellValue("MASSOLD"); + headerRow.createCell(9).setCellValue("MELSOLD"); + headerRow.createCell(10).setCellValue("MPCSOLD"); + headerRow.createCell(11).setCellValue("MPSSOLD"); + headerRow.createCell(12).setCellValue("MTFSOLD"); + headerRow.createCell(13).setCellValue("MWPSOLD"); + headerRow.createCell(14).setCellValue("MYOSOLD"); + headerRow.createCell(15).setCellValue("MAS"); + headerRow.createCell(16).setCellValue("MEL"); + headerRow.createCell(17).setCellValue("MPC"); + headerRow.createCell(18).setCellValue("MPS"); + headerRow.createCell(19).setCellValue("MTF"); + headerRow.createCell(20).setCellValue("MWP"); + headerRow.createCell(21).setCellValue("MYO"); + headerRow.createCell(22).setCellValue("MHZ"); + headerRow.createCell(23).setCellValue("MRT"); + headerRow.createCell(24).setCellValue("MBZ"); + + // 写入数据 + int rowNum = 1; + for (WeeklyHeavyStock weeklyHeavyStock : weeklyHeavyStockList) { + Row row = sheet.createRow(rowNum++); + row.createCell(0).setCellValue(weeklyHeavyStock.getPLU_CODE()); + row.createCell(1).setCellValue(weeklyHeavyStock.getCol()); + row.createCell(2).setCellValue(weeklyHeavyStock.getSize()); + row.createCell(3).setCellValue(weeklyHeavyStock.getItem_barcode()); + row.createCell(4).setCellValue(weeklyHeavyStock.getItem_name()); + row.createCell(5).setCellValue(weeklyHeavyStock.getCat()); + row.createCell(6).setCellValue(weeklyHeavyStock.getSub_cat()); + row.createCell(7).setCellValue(weeklyHeavyStock.getPrice_sales()); + row.createCell(8).setCellValue(weeklyHeavyStock.getMASSOLD()); + row.createCell(9).setCellValue(weeklyHeavyStock.getMELSOLD()); + row.createCell(10).setCellValue(weeklyHeavyStock.getMPCSOLD()); + row.createCell(11).setCellValue(weeklyHeavyStock.getMPSSOLD()); + row.createCell(12).setCellValue(weeklyHeavyStock.getMTFSOLD()); + row.createCell(13).setCellValue(weeklyHeavyStock.getMWPSOLD()); + row.createCell(14).setCellValue(weeklyHeavyStock.getMYOSOLD()); + row.createCell(15).setCellValue(weeklyHeavyStock.getMAS()); + row.createCell(16).setCellValue(weeklyHeavyStock.getMEL()); + row.createCell(17).setCellValue(weeklyHeavyStock.getMPC()); + row.createCell(18).setCellValue(weeklyHeavyStock.getMPS()); + row.createCell(19).setCellValue(weeklyHeavyStock.getMTF()); + row.createCell(20).setCellValue(weeklyHeavyStock.getMWP()); + row.createCell(21).setCellValue(weeklyHeavyStock.getMYO()); + row.createCell(22).setCellValue(weeklyHeavyStock.getMHZ()); + row.createCell(23).setCellValue(weeklyHeavyStock.getMRT()); + row.createCell(24).setCellValue(weeklyHeavyStock.getMBZ()); + } + + // 将工作簿写入文件 + try (FileOutputStream outputStream = new FileOutputStream(weeklyHeavyStockReportName)) { + workbook.write(outputStream); + } catch (IOException e) { + e.printStackTrace(); + } + + System.out.println("Excel file has been created successfully!"); + } + + + + private static List getQuarterlyProductGroupingList() { + List QuarterlyProductGroupingList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + Class.forName(JDBC_DRIVER); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + stmt = conn.createStatement(); + + String sql = "WITH CountedData AS (\n" + + " SELECT\n" + + " WHCODE,\n" + + " PLU_CODE,\n" + + " item_name,\n" + + " item_barcode,\n" + + " cat,\n" + + " sub_cat,\n" + + " Col,\n" + + " Size,\n" + + " price_sales,\n" + + " CASE WHEN WHCODE = 'MAS' THEN 1 ELSE 0 END AS MAS,\n" + + " CASE WHEN WHCODE = 'MEL' THEN 1 ELSE 0 END AS MEL,\n" + + " CASE WHEN WHCODE = 'MPC' THEN 1 ELSE 0 END AS MPC,\n" + + " CASE WHEN WHCODE = 'MPS' THEN 1 ELSE 0 END AS MPS,\n" + + " CASE WHEN WHCODE = 'MTF' THEN 1 ELSE 0 END AS MTF,\n" + + " CASE WHEN WHCODE = 'MWP' THEN 1 ELSE 0 END AS MWP,\n" + + " CASE WHEN WHCODE = 'MYO' THEN 1 ELSE 0 END AS MYO,\n" + + " CASE WHEN WHCODE = 'MHZ' THEN 1 ELSE 0 END AS MHZ,\n" + + " CASE WHEN WHCODE = 'MRT' THEN 1 ELSE 0 END AS MRT,\n" + + " CASE WHEN WHCODE = 'MBZ' THEN 1 ELSE 0 END AS MBZ\n" + + " FROM\n" + + " (\n" + + " SELECT\n" + + " WHCODE,\n" + + " PLU_CODE,\n" + + " item_name,\n" + + " item_code AS item_barcode,\n" + + " CATEGORY AS cat,\n" + + " SUB_CAT AS sub_cat,\n" + + " COLOR AS Col,\n" + + " SIZE AS SIZE,\n" + + " price_original as price_sales\n" + + " FROM\n" + + " v_MZG003A \n" + + " WHERE\n" + + " PLU_CODE IN (SELECT TOP 3\n" + + "PLU_CODE\n" + + "FROM v_MZG020B\n" + + "WHERE TRX_DATE >= '2024-03-04'\n" + + "AND TRX_DATE <= '2024-03-10'\n" + + "AND SH_CODE IN ('MAS', 'MEL', 'MPC', 'MPS', 'MTF', 'MWP', 'MYO')\n" + + "GROUP BY PLU_CODE\n" + + "ORDER BY count(1) desc)\n" + + " AND item_active = 'Y' \n" + + " AND WHCODE IN ('MAS', 'MEL', 'MPC', 'MPS', 'MTF', 'MWP', 'MYO', 'MHZ', 'MRT', 'MBZ')\n" + + " ) AS v \n" + + ") \n" + + "SELECT\n" + + " PLU_CODE,\n" + + " item_name,\n" + + " item_barcode,\n" + + " cat,\n" + + " sub_cat,\n" + + " Col,\n" + + " Size,\n" + + " price_sales,\n" + + " SUM(MAS) AS MAS,\n" + + " SUM(MEL) AS MEL,\n" + + " SUM(MPC) AS MPC,\n" + + " SUM(MPS) AS MPS,\n" + + " SUM(MTF) AS MTF,\n" + + " SUM(MWP) AS MWP,\n" + + " SUM(MYO) AS MYO,\n" + + " SUM(MHZ) AS MHZ,\n" + + " SUM(MRT) AS MRT,\n" + + " SUM(MBZ) AS MBZ\n" + + "FROM\n" + + " CountedData \n" + + "GROUP BY\n" + + " PLU_CODE,\n" + + " item_name,\n" + + " item_barcode,\n" + + " cat,\n" + + " sub_cat,\n" + + " Col,\n" + + " Size,\n" + + " price_sales"; + + ResultSet rs = stmt.executeQuery(sql); + + while (rs.next()) { + WeeklyHeavyStock weeklyHeavyStock = new WeeklyHeavyStock(); + weeklyHeavyStock.setPLU_CODE(rs.getString("PLU_CODE")); + weeklyHeavyStock.setItem_name(rs.getString("item_name")); + weeklyHeavyStock.setItem_barcode(rs.getString("item_barcode")); + weeklyHeavyStock.setCat(rs.getString("cat")); + weeklyHeavyStock.setSub_cat(rs.getString("sub_cat")); + weeklyHeavyStock.setCol(rs.getString("Col")); + weeklyHeavyStock.setSize(rs.getString("Size")); + weeklyHeavyStock.setPrice_sales(rs.getDouble("price_sales")); + weeklyHeavyStock.setMAS(rs.getInt("MAS")); + weeklyHeavyStock.setMEL(rs.getInt("MEL")); + weeklyHeavyStock.setMPC(rs.getInt("MPC")); + weeklyHeavyStock.setMPS(rs.getInt("MPS")); + weeklyHeavyStock.setMTF(rs.getInt("MTF")); + weeklyHeavyStock.setMWP(rs.getInt("MWP")); + weeklyHeavyStock.setMYO(rs.getInt("MYO")); + weeklyHeavyStock.setMHZ(rs.getInt("MHZ")); + weeklyHeavyStock.setMRT(rs.getInt("MRT")); + weeklyHeavyStock.setMBZ(rs.getInt("MBZ")); + QuarterlyProductGroupingList.add(weeklyHeavyStock); + } + sql = "SELECT\n" + + "PLU_CODE,\n" + + "ITEM_CODE,\n" + + "SH_CODE\n" + + "FROM\n" + + "v_MZG020B\n" + + "WHERE TRX_DATE >= '2024-03-04'\n" + + "AND TRX_DATE <= '2024-03-10'\n" + + "AND PLU_CODE IN (SELECT TOP 3\n" + + "PLU_CODE\n" + + "FROM v_MZG020B\n" + + "WHERE TRX_DATE >= '2024-03-04'\n" + + "AND TRX_DATE <= '2024-03-10'\n" + + "AND SH_CODE IN ('MAS', 'MEL', 'MPC', 'MPS', 'MTF', 'MWP', 'MYO')\n" + + "GROUP BY PLU_CODE\n" + + "ORDER BY count(1) desc)"; + + rs = stmt.executeQuery(sql); + + List relationShCodeList = new ArrayList<>(); + while (rs.next()) { + WeeklyHeavyStock weeklyHeavyStock = new WeeklyHeavyStock(); + weeklyHeavyStock.setPLU_CODE(rs.getString("PLU_CODE")); + weeklyHeavyStock.setItem_barcode(rs.getString("ITEM_CODE")); + weeklyHeavyStock.setSH_CODE(rs.getString("SH_CODE")); + relationShCodeList.add(weeklyHeavyStock); + } + for (WeeklyHeavyStock relationShCode : relationShCodeList) { + for (WeeklyHeavyStock quarterlyProductGrouping : QuarterlyProductGroupingList) { + if (quarterlyProductGrouping.getItem_barcode().equals(relationShCode.getItem_barcode())) { + if (relationShCode.getSH_CODE().equals("MPS ")) { + quarterlyProductGrouping.setMASSOLD(quarterlyProductGrouping.getMASSOLD() + 1); + } + else if (relationShCode.getSH_CODE().equals("MEL ")) { + quarterlyProductGrouping.setMELSOLD(quarterlyProductGrouping.getMELSOLD() + 1); + } + else if (relationShCode.getSH_CODE().equals("MPC ")) { + quarterlyProductGrouping.setMPCSOLD(quarterlyProductGrouping.getMPCSOLD() + 1); + } + else if (relationShCode.getSH_CODE().equals("MPS ")) { + quarterlyProductGrouping.setMPSSOLD(quarterlyProductGrouping.getMPSSOLD() + 1); + } + else if (relationShCode.getSH_CODE().equals("MTF ")) { + quarterlyProductGrouping.setMTFSOLD(quarterlyProductGrouping.getMTFSOLD() + 1); + } + else if (relationShCode.getSH_CODE().equals("MWP ")) { + quarterlyProductGrouping.setMWPSOLD(quarterlyProductGrouping.getMWPSOLD() + 1); + } + else if (relationShCode.getSH_CODE().equals("MYO ")) { + quarterlyProductGrouping.setMYOSOLD(quarterlyProductGrouping.getMYOSOLD() + 1); + } + } + } + } + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException | ClassNotFoundException se) { + se.printStackTrace(); + } finally { + try { + if (stmt != null) stmt.close(); + } catch (SQLException ignored) {} + try { + if (conn != null) conn.close(); + } catch (SQLException se) { + se.printStackTrace(); + } + } + System.out.println("Query execution completed!"); + return QuarterlyProductGroupingList; + } + + private static List getWeeklyHeavyStockList() { + List weeklyHeavyStockList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + Class.forName(JDBC_DRIVER); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + stmt = conn.createStatement(); + + String sql = "WITH CountedData AS (\n" + + " SELECT\n" + + " WHCODE,\n" + + " PLU_CODE,\n" + + " item_name,\n" + + " item_barcode,\n" + + " cat,\n" + + " sub_cat,\n" + + " Col,\n" + + " price_sales,\n" + + " CASE WHEN WHCODE = 'MAS' THEN 1 ELSE 0 END AS MAS,\n" + + " CASE WHEN WHCODE = 'MEL' THEN 1 ELSE 0 END AS MEL,\n" + + " CASE WHEN WHCODE = 'MPC' THEN 1 ELSE 0 END AS MPC,\n" + + " CASE WHEN WHCODE = 'MPS' THEN 1 ELSE 0 END AS MPS,\n" + + " CASE WHEN WHCODE = 'MTF' THEN 1 ELSE 0 END AS MTF,\n" + + " CASE WHEN WHCODE = 'MWP' THEN 1 ELSE 0 END AS MWP,\n" + + " CASE WHEN WHCODE = 'MYO' THEN 1 ELSE 0 END AS MYO,\n" + + " CASE WHEN WHCODE = 'MHZ' THEN 1 ELSE 0 END AS MHZ,\n" + + " CASE WHEN WHCODE = 'MRT' THEN 1 ELSE 0 END AS MRT,\n" + + " CASE WHEN WHCODE = 'MBZ' THEN 1 ELSE 0 END AS MBZ,\n" + + " SUM(1) OVER (PARTITION BY PLU_CODE, Col) AS subtotal,\n" + + " SUM(1) OVER (PARTITION BY PLU_CODE) AS \"G.TLT\"\n" + + " FROM\n" + + " (\n" + + " SELECT\n" + + " WHCODE,\n" + + " PLU_CODE,\n" + + " item_name,\n" + + " item_code AS item_barcode,\n" + + " CATEGORY AS cat,\n" + + " SUB_CAT AS sub_cat,\n" + + " COLOR AS Col,\n" + + " SIZE AS SIZE,\n" + + " price_original as price_sales\n" + + " FROM\n" + + " v_MZG003A \n" + + " WHERE\n" + + " PLU_CODE IN (\n" + + " SELECT TOP 30 PLU_CODE \n" + + " FROM v_MZG003A \n" + + " WHERE item_active = 'Y' \n" + + " GROUP BY PLU_CODE \n" + + " ORDER BY COUNT ( 1 ) DESC\n" + + " ) \n" + + " AND item_active = 'Y' \n" + + " AND WHCODE IN ('MAS', 'MEL', 'MPC', 'MPS', 'MTF', 'MWP', 'MYO', 'MHZ', 'MRT', 'MBZ')\n" + + " ) AS v \n" + + ") \n" + + "SELECT\n" + + " PLU_CODE,\n" + + " item_name,\n" + + " item_barcode,\n" + + " cat,\n" + + " sub_cat,\n" + + " Col,\n" + + " price_sales,\n" + + " SUM(MAS) AS MAS,\n" + + " SUM(MEL) AS MEL,\n" + + " SUM(MPC) AS MPC,\n" + + " SUM(MPS) AS MPS,\n" + + " SUM(MTF) AS MTF,\n" + + " SUM(MWP) AS MWP,\n" + + " SUM(MYO) AS MYO,\n" + + " SUM(MHZ) AS MHZ,\n" + + " SUM(MRT) AS MRT,\n" + + " SUM(MBZ) AS MBZ,\n" + + " SUM(MAS + MEL + MPC + MPS + MTF + MWP + MYO + MHZ + MRT + MBZ) AS TLT,\n" + + " subtotal,\n" + + " \"G.TLT\"\n" + + "FROM\n" + + " CountedData \n" + + "GROUP BY\n" + + " PLU_CODE,\n" + + " item_name,\n" + + " item_barcode,\n" + + " cat,\n" + + " sub_cat,\n" + + " Col,\n" + + " price_sales,\n" + + " subtotal,\n" + + " \"G.TLT\"\n" + + "ORDER BY \"G.TLT\" DESC, PLU_CODE ASC;\n"; + + ResultSet rs = stmt.executeQuery(sql); + + while (rs.next()) { + WeeklyHeavyStock weeklyHeavyStock = new WeeklyHeavyStock(); + weeklyHeavyStock.setPLU_CODE(rs.getString("PLU_CODE")); + weeklyHeavyStock.setItem_name(rs.getString("item_name")); + weeklyHeavyStock.setItem_barcode(rs.getString("item_barcode")); + weeklyHeavyStock.setCat(rs.getString("cat")); + weeklyHeavyStock.setSub_cat(rs.getString("sub_cat")); + weeklyHeavyStock.setCol(rs.getString("Col")); + weeklyHeavyStock.setPrice_sales(rs.getDouble("price_sales")); + weeklyHeavyStock.setMAS(rs.getInt("MAS")); + weeklyHeavyStock.setMEL(rs.getInt("MEL")); + weeklyHeavyStock.setMPC(rs.getInt("MPC")); + weeklyHeavyStock.setMPS(rs.getInt("MPS")); + weeklyHeavyStock.setMTF(rs.getInt("MTF")); + weeklyHeavyStock.setMWP(rs.getInt("MWP")); + weeklyHeavyStock.setMYO(rs.getInt("MYO")); + weeklyHeavyStock.setMHZ(rs.getInt("MHZ")); + weeklyHeavyStock.setMRT(rs.getInt("MRT")); + weeklyHeavyStock.setMBZ(rs.getInt("MBZ")); + weeklyHeavyStock.setTLT(rs.getInt("TLT")); + weeklyHeavyStock.setSubtotal(rs.getInt("subtotal")); + weeklyHeavyStock.setG_TLT(rs.getInt("G.TLT")); + weeklyHeavyStockList.add(weeklyHeavyStock); + } + + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException | ClassNotFoundException se) { + se.printStackTrace(); + } finally { + try { + if (stmt != null) stmt.close(); + } catch (SQLException ignored) {} + try { + if (conn != null) conn.close(); + } catch (SQLException se) { + se.printStackTrace(); + } + } + System.out.println("Query execution completed!"); + return weeklyHeavyStockList; + } + + private static List getTransactionSummaryList() { + List transactionSummaryList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + // 注册 JDBC 驱动器 + Class.forName(JDBC_DRIVER); + + // 打开一个连接 + System.out.println("连接数据库..."); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + + // 执行查询 + System.out.println("创建声明..."); + stmt = conn.createStatement(); + String sql; + + // 构建完整的 SQL 查询语句 + sql = "SELECT TOP 30\n" + + " PLU_CODE,\n" + + " ITEM_NAME,\n" + + " CATEGORY,\n" + + " SUB_CAT,\n" + + " PRICE_ORIGINAL,\n" + + " COUNT(1) AS totalSaleNum,\n" + + " SUM(CASE WHEN SH_CODE = 'MAS' THEN 1 ELSE 0 END) AS MAS,\n" + + " SUM(CASE WHEN SH_CODE = 'MEL' THEN 1 ELSE 0 END) AS MEL,\n" + + " SUM(CASE WHEN SH_CODE = 'MPC' THEN 1 ELSE 0 END) AS MPC,\n" + + " SUM(CASE WHEN SH_CODE = 'MPS' THEN 1 ELSE 0 END) AS MPS,\n" + + " SUM(CASE WHEN SH_CODE = 'MTF' THEN 1 ELSE 0 END) AS MTF,\n" + + " SUM(CASE WHEN SH_CODE = 'MWP' THEN 1 ELSE 0 END) AS MWP,\n" + + " SUM(CASE WHEN SH_CODE = 'MYO' THEN 1 ELSE 0 END) AS MYO\n" + + "FROM\n" + + " v_MZG020B\n" + + "WHERE\n" + + " TRX_DATE >= '2024-01-08'\n" + + " AND TRX_DATE <= '2024-01-14'\n" + + "GROUP BY\n" + + " PLU_CODE, ITEM_NAME, CATEGORY, SUB_CAT, PRICE_ORIGINAL\n" + + "ORDER BY \n" + + " totalSaleNum DESC, PLU_CODE;"; + ResultSet rs = stmt.executeQuery(sql); + + // 处理结果集 + while (rs.next()) { + TransactionSummary summary = new TransactionSummary(); + summary.setPLU_CODE(rs.getString("PLU_CODE")); + summary.setItemName(rs.getString("ITEM_NAME")); + summary.setCATEGORY(rs.getString("CATEGORY")); + summary.setSUB_CAT(rs.getString("SUB_CAT")); + summary.setPriceOriginal(rs.getDouble("PRICE_ORIGINAL")); + summary.setTotalSaleNum(rs.getInt("totalSaleNum")); + summary.setMAS_count(rs.getInt("MAS")); + summary.setMEL_count(rs.getInt("MEL")); + summary.setMPC_count(rs.getInt("MPC")); + summary.setMPS_count(rs.getInt("MPS")); + summary.setMTF_count(rs.getInt("MTF")); + summary.setMWP_count(rs.getInt("MWP")); + summary.setMYO_count(rs.getInt("MYO")); + transactionSummaryList.add(summary); + } + + List pluCodeList = transactionSummaryList.stream().map(TransactionSummary::getPLU_CODE).collect(Collectors.toList()); + StringBuilder inClause = new StringBuilder("("); + for (String pluCode : pluCodeList) { + inClause.append("'").append(pluCode).append("',"); + } + inClause.deleteCharAt(inClause.length() - 1); // 删除最后一个逗号 + inClause.append(")"); + + // 构建完整的 SQL 查询语句 + sql = "SELECT\n" + + "PLU_CODE,\n" + + "COUNT(1) AS retailOnHand\n" + + "FROM v_MZG003A\n" + + "WHERE PLU_CODE IN " + inClause.toString() + "\n" + + "GROUP BY PLU_CODE;"; + rs = stmt.executeQuery(sql); + List retailOnHandList = new ArrayList<>(); + while (rs.next()) { + TransactionSummary summary = new TransactionSummary(); + summary.setPLU_CODE(rs.getString("PLU_CODE")); + summary.setRetailOnHand(rs.getInt("retailOnHand")); + retailOnHandList.add(summary); + } + for (TransactionSummary transactionSummary : transactionSummaryList) { + for (TransactionSummary summary : retailOnHandList) { + if (transactionSummary.getPLU_CODE().equals(summary.getPLU_CODE())) { + transactionSummary.setRetailOnHand(summary.getRetailOnHand()); + break; + } + } + } + + sql = "SELECT plu_code,toshopdate,lastwk_salesqty FROM v_MZG019C WHERE plu_code in" + inClause; + rs = stmt.executeQuery(sql); + List toShopDateList = new ArrayList<>(); + while (rs.next()) { + TransactionSummary summary = new TransactionSummary(); + summary.setPLU_CODE(rs.getString("plu_code")); + summary.setToShopDate(rs.getDate("toshopdate")); + summary.setLwSalesQty(rs.getInt("lastwk_salesqty")); + toShopDateList.add(summary); + } + + for (TransactionSummary transactionSummary : transactionSummaryList) { + for (TransactionSummary toShopDate : toShopDateList) { + if (transactionSummary.getPLU_CODE().equals(toShopDate.getPLU_CODE())) { + transactionSummary.setToShopDate(toShopDate.getToShopDate()); + transactionSummary.setSalesDay(calculateDaysDifference(toShopDate.getToShopDate())); + transactionSummary.setLwSalesQty(toShopDate.getLwSalesQty()); + break; + } + } + } + + for (TransactionSummary transactionSummary : transactionSummaryList) { + int ttlSalesQty = transactionSummary.getTotalSaleNum(); + int retailOnHand = transactionSummary.getRetailOnHand(); + int toRetailQty = ttlSalesQty + retailOnHand; + + double result = (double) ttlSalesQty / toRetailQty; + // 将结果四舍五入到两位小数 + double roundedResult = Math.round(result * 100.0) / 100.0; + // 将销售率转换为百分比形式 + String salesRate = String.format("%.0f%%", roundedResult * 100); + + transactionSummary.setToRetailQty(toRetailQty); + transactionSummary.setSalesRate(salesRate); + } + + // 清理环境 + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException se) { + // 处理 JDBC 错误 + se.printStackTrace(); + } catch (Exception e) { + // 处理 Class.forName 错误 + e.printStackTrace(); + } finally { + // 关闭资源 + try { + if (stmt != null) stmt.close(); + } catch (SQLException se2) { + } // 什么都不做 + try { + if (conn != null) conn.close(); + } catch (SQLException se) { + se.printStackTrace(); + } + } + System.out.println("查询执行完成!"); + return transactionSummaryList; + } + + public static int calculateDaysDifference(Date toShopDate) { + // 获取当前时间的毫秒数 + long currentTimeMillis = System.currentTimeMillis(); + + // 获取toShopDate的毫秒数 + long toShopTimeMillis = toShopDate.getTime(); + + // 计算毫秒差,并转换为天数,并向上取整 + int daysDifference = (int) Math.ceil((currentTimeMillis - toShopTimeMillis) / (1000.0 * 60 * 60 * 24)); + + return daysDifference; + } + + private static List getCustomerData() { + List customerDataList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + // 注册 JDBC 驱动器 + Class.forName(JDBC_DRIVER); + + // 打开一个连接 + System.out.println("连接数据库..."); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + + // 执行查询 + System.out.println("创建声明..."); + stmt = conn.createStatement(); + String sql; +// // 构建 IN 子句的字符串,用于添加到 SQL 查询中 +// StringBuilder inClause = new StringBuilder("("); +// for (String code : collect) { +// inClause.append("'").append(code).append("',"); +// } +// inClause.deleteCharAt(inClause.length() - 1); // 删除最后一个逗号 +// inClause.append(")"); + + // 构建完整的 SQL 查询语句 + sql = "SELECT * \n" + + "FROM V_RW0095B\n" + + "WHERE join_date >= DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()) - 1, 0)\n" + + "AND mbr_group != 'NONMBR'\n" + + "ORDER BY join_date DESC"; + ResultSet rs = stmt.executeQuery(sql); + + + // 处理结果集 + while (rs.next()) { + // 将每行数据转换为 CustomerData 对象并添加到列表中 + CustomerData customer = new CustomerData(); + customer.setMbrCode(rs.getString("mbr_code")); + customer.setMbrName(rs.getString("mbr_name")); + customer.setMbrMobile(rs.getString("mbr_mobile")); + customer.setMbrGroup(rs.getString("mbr_group")); + customer.setMbrStatus(rs.getString("mbr_status")); + customer.setJoinDate(rs.getDate("join_date")); + customer.setMbrIssue(rs.getString("mbr_issue")); + customer.setBirthMonth(rs.getInt("birth_m")); + customer.setMbrSex(rs.getString("mbr_sex")); + customer.setOffBonus(rs.getDouble("off_bonus")); + customer.setEffBonus(rs.getDouble("eff_bonus")); + customer.setSumBonus(rs.getDouble("sum_bonus")); + customerDataList.add(customer); + + } + + // 清理环境 + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException se) { + // 处理 JDBC 错误 + se.printStackTrace(); + } catch (Exception e) { + // 处理 Class.forName 错误 + e.printStackTrace(); + } finally { + // 关闭资源 + try { + if (stmt != null) stmt.close(); + } catch (SQLException se2) { + } // 什么都不做 + try { + if (conn != null) conn.close(); + } catch (SQLException se) { + se.printStackTrace(); + } + } + System.out.println("查询执行完成!"); + return customerDataList; + } + + private static List getTransactionNewCustomerList() { + List transactionNewCustomerList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + // 注册 JDBC 驱动器 + Class.forName(JDBC_DRIVER); + + // 打开一个连接 + System.out.println("连接数据库..."); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + + // 执行查询 + System.out.println("创建声明..."); + stmt = conn.createStatement(); + String sql; + + // 构建完整的 SQL 查询语句 + sql = "SELECT * FROM v_MZG002b\n" + + "WHERE join_date >= DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()) - 1, 0)\n" + + "AND join_date <= DATEADD(DAY, -1, DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0))\n" + + "AND VIP_GRADE != 'WALK IN'\n" + + "AND VIP_GRADE != 'OLD VIP-VIPP'\n" + + "AND VIP_GRADE != 'OLD VIP-VIPC'\n" + + "ORDER BY join_date DESC"; + ResultSet rs = stmt.executeQuery(sql); + + + // 处理结果集 + while (rs.next()) { + // 将每行数据转换为 TransactionNewCustomer 对象并添加到列表中 + TransactionNewCustomer transactionNewCustomer = new TransactionNewCustomer(); + transactionNewCustomer.setTrxNo(rs.getString("TRX_NO")); + transactionNewCustomer.setShCode(rs.getString("SH_CODE")); + transactionNewCustomer.setSalesmanName(rs.getString("SALEMAN_NAME")); + transactionNewCustomer.setVipGrade(rs.getString("VIP_GRADE")); + transactionNewCustomer.setSalesAmt(rs.getDouble("SALES_AMT")); + transactionNewCustomer.setUserMember(rs.getString("USER_MEMBER")); + transactionNewCustomer.setMbrName(rs.getString("MBR_NAME")); + transactionNewCustomer.setMbrMobile(rs.getString("mbr_mobile")); + transactionNewCustomer.setJoinDate(rs.getDate("join_date")); + transactionNewCustomerList.add(transactionNewCustomer); + } + sql = "SELECT\n" + + "aaa.TRX_NO,\n" + + "sum(bbb.pay_bas_amt) as sumPayBasAmt\n" + + "FROM\n" + + "v_MZG002b aaa, V_MZG013 bbb\n" + + "WHERE aaa.TRX_NO = bbb.trx_no\n" + + "AND aaa.join_date >= DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()) - 1, 0)\n" + + "AND aaa.join_date <= DATEADD(DAY, -1, DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0))\n" + + "AND aaa.VIP_GRADE != 'WALK IN'\n" + + "AND aaa.VIP_GRADE != 'OLD VIP-VIPP'\n" + + "AND aaa.VIP_GRADE != 'OLD VIP-VIPC'\n" + + "AND bbb.pay_desc != 'Bonus'\n" + + "AND bbb.pay_desc != 'mi-tu Cash Coupon'\n" + + "GROUP BY aaa.TRX_NO"; + ResultSet rs1 = stmt.executeQuery(sql); + List transactionNewCustomerListSumPayBasAmt = new ArrayList<>(); + while (rs1.next()) { + TransactionNewCustomer transactionNewCustomer = new TransactionNewCustomer(); + transactionNewCustomer.setTrxNo(rs1.getString("TRX_NO")); + transactionNewCustomer.setSumPayBasAmt(rs1.getDouble("sumPayBasAmt")); + transactionNewCustomerListSumPayBasAmt.add(transactionNewCustomer); + } + Iterator iterator = transactionNewCustomerList.iterator(); + while (iterator.hasNext()) { + TransactionNewCustomer transactionNewCustomer = iterator.next(); + boolean exist = false; + for (TransactionNewCustomer newCustomer : transactionNewCustomerListSumPayBasAmt) { + if (newCustomer.getTrxNo().equals(transactionNewCustomer.getTrxNo())) { + exist = true; + break; + } + } + if (!exist) { + iterator.remove(); + } + } + + for (TransactionNewCustomer transactionNewCustomer : transactionNewCustomerListSumPayBasAmt) { + for (TransactionNewCustomer newCustomer : transactionNewCustomerList) { + if (newCustomer.getTrxNo().equals(transactionNewCustomer.getTrxNo())) { + newCustomer.setSalesAmt(transactionNewCustomer.getSumPayBasAmt()); + break; + } + } + } + + // 清理环境 + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException se) { + // 处理 JDBC 错误 + se.printStackTrace(); + } catch (Exception e) { + // 处理 Class.forName 错误 + e.printStackTrace(); + } finally { + // 关闭资源 + try { + if (stmt != null) stmt.close(); + } catch (SQLException se2) { + } // 什么都不做 + try { + if (conn != null) conn.close(); + } catch (SQLException se) { + se.printStackTrace(); + } + } + System.out.println("查询执行完成!"); + return transactionNewCustomerList; + } + + public static void exportToExcelCustomerPurchaseReport(List customerDataList, String filePath) throws IOException { + File file = new File(filePath); + boolean fileExists = file.exists() && file.length() > 0; // 检查文件是否存在且非空 + + // 如果文件不存在或者为空,则创建一个新的 Workbook + Workbook workbook = fileExists ? WorkbookFactory.create(file) : new XSSFWorkbook(); + + // 创建一个新的 Sheet 或获取现有的 Sheet + Sheet sheet = workbook.getSheet("Customer Data"); + if (sheet == null) { + sheet = workbook.createSheet("Customer Data"); + } + + // 创建标题行 + Row headerRow = sheet.getRow(0); + if (headerRow == null) { + headerRow = sheet.createRow(0); + } + + // 获取当前年月 + YearMonth currentYearMonth = YearMonth.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM"); + String[] headers = new String[25]; + headers[0] = "mbrCode"; + headers[1] = "mbrName"; + headers[2] = "mbrMobile"; + headers[3] = "mbrGroup"; + headers[4] = "mbrStatus"; + headers[5] = "joinDate"; + headers[6] = "mbrIssue"; + headers[7] = "birthMonth"; + headers[8] = "mbrSex"; + headers[9] = "offBonus"; + headers[10] = "effBonus"; + headers[11] = "sumBonus"; + headers[12] = "thisMonth"; + + // 添加过去十一个月的年月 + for (int i = 0; i < 11; i++) { + headers[13 + i] = currentYearMonth.minusMonths(i + 1).format(formatter); + } + for (int i = 0; i < headers.length; i++) { + Cell cell = headerRow.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); + cell.setCellValue(headers[i]); + } + + // 写入数据 + int rowNum = sheet.getLastRowNum() + 1; + for (CustomerData customer : customerDataList) { + Row row = sheet.createRow(rowNum++); + + row.createCell(0).setCellValue(customer.getMbrCode()); + row.createCell(1).setCellValue(customer.getMbrName()); + row.createCell(2).setCellValue(customer.getMbrMobile()); + row.createCell(3).setCellValue(customer.getMbrGroup()); + row.createCell(4).setCellValue(customer.getMbrStatus()); + if (customer.getJoinDate() != null) { + row.createCell(5).setCellValue(customer.getJoinDate().toString()); + } + row.createCell(6).setCellValue(customer.getMbrIssue()); + row.createCell(7).setCellValue(customer.getBirthMonth()); + row.createCell(8).setCellValue(customer.getMbrSex()); + row.createCell(9).setCellValue(customer.getOffBonus()); + row.createCell(10).setCellValue(customer.getEffBonus()); + row.createCell(11).setCellValue(customer.getSumBonus()); + row.createCell(12).setCellValue(customer.getThisMonth()); + row.createCell(13).setCellValue(customer.getMonth1()); + row.createCell(14).setCellValue(customer.getMonth2()); + row.createCell(15).setCellValue(customer.getMonth3()); + row.createCell(16).setCellValue(customer.getMonth4()); + row.createCell(17).setCellValue(customer.getMonth5()); + row.createCell(18).setCellValue(customer.getMonth6()); + row.createCell(19).setCellValue(customer.getMonth7()); + row.createCell(20).setCellValue(customer.getMonth8()); + row.createCell(21).setCellValue(customer.getMonth9()); + row.createCell(22).setCellValue(customer.getMonth10()); + row.createCell(23).setCellValue(customer.getMonth11()); + row.createCell(24).setCellValue(customer.getMonth12()); + } + + // 将Workbook写入文件 + try (FileOutputStream outputStream = new FileOutputStream(file)) { + workbook.write(outputStream); + } + + System.out.println("Excel file has been created successfully!"); + } + + public static List retrieveCustomerData(List collect) { + List customerDataList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + // 注册 JDBC 驱动器 + Class.forName(JDBC_DRIVER); + + // 打开一个连接 + System.out.println("连接数据库..."); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + + // 执行查询 + System.out.println("创建声明..."); + stmt = conn.createStatement(); + String sql; + // 构建 IN 子句的字符串,用于添加到 SQL 查询中 + StringBuilder inClause = new StringBuilder("("); + for (String code : collect) { + inClause.append("'").append(code).append("',"); + } + inClause.deleteCharAt(inClause.length() - 1); // 删除最后一个逗号 + inClause.append(")"); + + // 构建完整的 SQL 查询语句 + sql = "SELECT * FROM V_RW0095B WHERE mbr_code IN " + inClause.toString(); + ResultSet rs = stmt.executeQuery(sql); + + + // 处理结果集 + while (rs.next()) { + // 将每行数据转换为 CustomerData 对象并添加到列表中 + CustomerData customer = new CustomerData(); + customer.setMbrCode(rs.getString("mbr_code")); + customer.setMbrName(rs.getString("mbr_name")); + customer.setMbrMobile(rs.getString("mbr_mobile")); + customer.setMbrGroup(rs.getString("mbr_group")); + customer.setMbrStatus(rs.getString("mbr_status")); + customer.setJoinDate(rs.getDate("join_date")); + customer.setMbrIssue(rs.getString("mbr_issue")); + customer.setBirthMonth(rs.getInt("birth_m")); + customer.setMbrSex(rs.getString("mbr_sex")); + customer.setOffBonus(rs.getDouble("off_bonus")); + customer.setEffBonus(rs.getDouble("eff_bonus")); + customer.setSumBonus(rs.getDouble("sum_bonus")); + customerDataList.add(customer); + + } + + // 清理环境 + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException se) { + // 处理 JDBC 错误 + se.printStackTrace(); + } catch (Exception e) { + // 处理 Class.forName 错误 + e.printStackTrace(); + } finally { + // 关闭资源 + try { + if (stmt != null) stmt.close(); + } catch (SQLException se2) { + } // 什么都不做 + try { + if (conn != null) conn.close(); + } catch (SQLException se) { + se.printStackTrace(); + } + } + System.out.println("查询执行完成!"); + return customerDataList; + } + + public static List retrieveTransactionData() { + List transactionDataList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + // 注册 JDBC 驱动器 + Class.forName(JDBC_DRIVER); + + // 打开一个连接 + System.out.println("连接数据库..."); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + + // 执行查询 + System.out.println("创建声明..."); + stmt = conn.createStatement(); + String sql; + sql = "SELECT \n" + + " user_member,\n" + + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) AND trx_date <= GETDATE() THEN pay_bas_amt ELSE 0 END) AS thisMonth,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) THEN pay_bas_amt ELSE 0 END) AS month1,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -2, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month2,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -2, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month3,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -4, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -3, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month4,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -5, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -4, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month5,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -6, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -5, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month6,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -7, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -6, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month7,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -8, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -7, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month8,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -9, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -8, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month9,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -10, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -9, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month10,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -11, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -10, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month11,\n" + + " SUM(CASE WHEN trx_date >= DATEADD(MONTH, -12, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) AND trx_date < DATEADD(MONTH, -11, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) THEN pay_bas_amt ELSE 0 END) AS month12\n" + + "FROM \n" + + " V_MZG013\n" + + "WHERE \n" + + " trx_date >= DATEADD(MONTH, -12, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))\n" + + " AND user_member IS NOT NULL\n" + + " AND pay_desc != 'Bonus'\n" + + " AND pay_desc != 'mi-tu Cash Coupon'\n" + + "GROUP BY \n" + + " user_member\n"; + + ResultSet rs = stmt.executeQuery(sql); +// rs.setFetchSize(500); + int a = 0; + // 处理结果集 + while (rs.next()) { + a ++; +// System.out.println(a); + // 将每行数据转换为 TransactionData 对象并添加到列表中 + TransactionData transaction = new TransactionData(); + transaction.setUserMember(rs.getString("user_member")); + +// transaction.setMbrName(rs.getString("mbr_name")); + transaction.setThisMonth(rs.getDouble("thisMonth")); + transaction.setMonth1(rs.getDouble("month1")); + transaction.setMonth2(rs.getDouble("month2")); + transaction.setMonth3(rs.getDouble("month3")); + transaction.setMonth4(rs.getDouble("month4")); + transaction.setMonth5(rs.getDouble("month5")); + transaction.setMonth6(rs.getDouble("month6")); + transaction.setMonth7(rs.getDouble("month7")); + transaction.setMonth8(rs.getDouble("month8")); + transaction.setMonth9(rs.getDouble("month9")); + transaction.setMonth10(rs.getDouble("month10")); + transaction.setMonth11(rs.getDouble("month11")); + transaction.setMonth12(rs.getDouble("month12")); + + transactionDataList.add(transaction); + } + + // 清理环境 + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException | ClassNotFoundException e) { + // 处理异常 + e.printStackTrace(); + } + System.out.println("查询执行完成!"); + return transactionDataList; + } + + // 示例:导出数据到CSV文件 + private static void exportToCSV(ResultSet resultSet, String filePath) throws SQLException, IOException { + FileWriter writer = new FileWriter(filePath); + + while (resultSet.next()) { + // 将结果写入CSV文件 + // 这里需要根据实际情况将数据写入CSV文件 + } + + writer.close(); + } +} diff --git a/src/main/java/com/mixi/common/tasks/mituExportEntity/CustomerData.java b/src/main/java/com/mixi/common/tasks/mituExportEntity/CustomerData.java new file mode 100644 index 0000000..87d38f8 --- /dev/null +++ b/src/main/java/com/mixi/common/tasks/mituExportEntity/CustomerData.java @@ -0,0 +1,35 @@ +package com.mixi.common.tasks.mituExportEntity; + +import lombok.Data; + +import java.util.Date; + +@Data +public class CustomerData { + private String mbrCode; + private String mbrName; + private String mbrMobile; + private String mbrGroup; + private String mbrStatus; + private Date joinDate; + private String mbrIssue; + private int birthMonth; + private String mbrSex; + private double offBonus; + private double effBonus; + private double sumBonus; + + private double thisMonth; + private double month1; + private double month2; + private double month3; + private double month4; + private double month5; + private double month6; + private double month7; + private double month8; + private double month9; + private double month10; + private double month11; + private double month12; +} diff --git a/src/main/java/com/mixi/common/tasks/mituExportEntity/MiTuProductStock.java b/src/main/java/com/mixi/common/tasks/mituExportEntity/MiTuProductStock.java new file mode 100644 index 0000000..d084eb6 --- /dev/null +++ b/src/main/java/com/mixi/common/tasks/mituExportEntity/MiTuProductStock.java @@ -0,0 +1,10 @@ +package com.mixi.common.tasks.mituExportEntity; + +import lombok.Data; + +@Data +public class MiTuProductStock { + private String whCode; + private String size; + private Integer num; +} diff --git a/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionData.java b/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionData.java new file mode 100644 index 0000000..ff3f45a --- /dev/null +++ b/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionData.java @@ -0,0 +1,162 @@ +package com.mixi.common.tasks.mituExportEntity; + +import lombok.Data; + +import java.sql.Date; +import java.sql.Timestamp; + +@Data +public class TransactionData { + private String trxNo; + private Timestamp trxDate; + private String trxType; + private String trxStatus; + private double trxTotQty; + private String currCode; + private double exchRate; + private double discountPerc; + private double trxAccAmt; + private double trxBasAmt; + private double outstandAmt; + private double receiveAmt; + private double changeAmt; + private double trxTotBonus; + private String depositNo; + private double depositAmt; + private String depositStatus; + private String trxAmtDesc; + private String remark; + private String shCode; + private String whCodeFrom; + private String whCodeTo; + private String issuedBy; + private String clientCode; + private String clientName; + private String salesmanCode; + private String ctypeCode; + private Timestamp updatedOn; + private String docType; + private String refNo; + private String adjType; + private String refType; + private String orderNo; + private String recoverF; + private String recoverT; + private String requestBy; + private String error; + private Timestamp authorizedDate; + private String authorizedBy; + private String changeCurrCode; + private double chgRate; + private String cashier; + private String cashiNo; + private String salesmanCode2; + private String classId; + private double disAmt; + private String acStatus; + private String reprint; + private String alt1; + private String alt2; + private String alt3; + private String alt4; + private String alt5; + private Date altD1; + private Date altD2; + private Date altD3; + private Date altD4; + private Date altD5; + private String salesmanCode3; + private String contractNo; + private Timestamp expireDate; + private double depositNetAmt; + private String clientRestriction; + private String refStatus; + private double mbrDis; + private double pmtDiscount; + private double pmtAmount; + private String pmtNo; + private String refCode; + private String docApproved; + private String refractionNo; + private double ccpTot; + private double ccpRed; + private double ccpExpired; + private int printedTimes; + private String pickupShop; + private Date deliveryDate; + private String deliveryTime; + private String wsCode; + private String clCode; + private String clDesc; + private String ratio; + private String userMember; + private String hflag; + private String issueShop; + private String hoUpdBy; + private Timestamp hoUpdOn; + private double bonusExpired; + private double bonusRed; + private Timestamp confirmedOn; + private String confirmedBy; + private String docConfirmed; + private String brNo; + private double changeAmt2; + private Date salesDate; + private String mbrName; + private String canEntryDis; + private String reactiveClient; + private String reactiveMbr; + private String shUpdBy; + private Timestamp shUpdOn; + private double tax1; + private double tax2; + private double tax3; + private double tax4; + private double tax5; + private String altChar1; + private String altChar2; + private String altChar3; + private String altChar4; + private String altChar5; + private double altNum1; + private double altNum2; + private double altNum3; + private double altNum4; + private double altNum5; + private String newClient; + private String newMbr; + private double pmtExtraDiscount; + private double pmtExtraAmount; + private double manualDiscount; + private double manualAmount; + private double usermbrDiscount; + private double clientDiscount; + private String holdVoid; + private double payBasAmt; + private String payDesc; + private String payCode; + private String cardNo; + private String payCurr; + private double payCurrAmt; + private String onbehalfPaid; + private String onbehalfLoc; + private String oldCardNo; + private int trxYear; + private int trxMonth; + + private double sumAmt; + private double thisMonth; + private double month1; + private double month2; + private double month3; + private double month4; + private double month5; + private double month6; + private double month7; + private double month8; + private double month9; + private double month10; + private double month11; + private double month12; +} + diff --git a/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionNewCustomer.java b/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionNewCustomer.java new file mode 100644 index 0000000..ca5cffd --- /dev/null +++ b/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionNewCustomer.java @@ -0,0 +1,53 @@ +package com.mixi.common.tasks.mituExportEntity; + +import lombok.Data; + +import java.util.Date; + +@Data +public class TransactionNewCustomer { + private Date trxDate; + private String shCode; + private String trxType; + private String trxNo; + private String docType; + private String salesmanCode; + private String salesmanName; + private String vipGroup; + private String vipGrade; + private double salesQty; + private double salesAmt; + private String userMember; + private String mbrName; + private String remark; + private String nationality; + private double balanceAmt; + private double shareBalanceAmt; + private String trxStatus; + private int trxYear; + private int trxMonth; + private int trxDay; + private int trxHour; + private int trxMinute; + private String crnoteStatus; + private double nonshareBalanceAmt; + private double netBalanceAmt; + private String mbrStatus; + private String mbrMobile; + private String mbrPhone; + private String mbrId; + private String mbrAdd; + private String mbrEmail; + private String mbrGroup; + private Date joinDate; + private Date mbrExpireOn; + private String mbrIssue; + private String memberType; + private String birthMonth; + private String mbrRemark; + private String mbrPager; + private String oldCardNo; + + private double sumPayBasAmt; +} + diff --git a/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionSummary.java b/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionSummary.java new file mode 100644 index 0000000..a7bce9a --- /dev/null +++ b/src/main/java/com/mixi/common/tasks/mituExportEntity/TransactionSummary.java @@ -0,0 +1,32 @@ +package com.mixi.common.tasks.mituExportEntity; + +import lombok.Data; + +import java.util.Date; + +@Data +public class TransactionSummary { + private String PLU_CODE; + private String ItemName; + private String CATEGORY; + private String SUB_CAT; + private int totalSaleNum; + private int retailOnHand; + private double priceOriginal; + private int MAS_count; + private int MEL_count; + private int MPC_count; + private int MPS_count; + private int MTF_count; + private int MWP_count; + private int MYO_count; + + private Date toShopDate; + private int salesDay; + private int toRetailQty; +// private int ttlSalesQty; + private int lwSalesQty; + private String salesRate; + +} + diff --git a/src/main/java/com/mixi/common/tasks/mituExportEntity/WeeklyHeavyStock.java b/src/main/java/com/mixi/common/tasks/mituExportEntity/WeeklyHeavyStock.java new file mode 100644 index 0000000..e8ae5da --- /dev/null +++ b/src/main/java/com/mixi/common/tasks/mituExportEntity/WeeklyHeavyStock.java @@ -0,0 +1,38 @@ +package com.mixi.common.tasks.mituExportEntity; + +import lombok.Data; + +@Data +public class WeeklyHeavyStock { + private String PLU_CODE; + private String item_name; + private String item_barcode; + private String cat; + private String sub_cat; + private String Col; + private String Size; + private double price_sales; + private int MAS; + private int MEL; + private int MPC; + private int MPS; + private int MTF; + private int MWP; + private int MYO; + private int MHZ; + private int MRT; + private int MBZ; + private int TLT; + private int subtotal; + private int G_TLT; + + private String SH_CODE; + + private int MASSOLD; + private int MELSOLD; + private int MPCSOLD; + private int MPSSOLD; + private int MTFSOLD; + private int MWPSOLD; + private int MYOSOLD; +} diff --git a/src/main/java/com/mixi/common/utils/AccessLimitUtils.java b/src/main/java/com/mixi/common/utils/AccessLimitUtils.java new file mode 100644 index 0000000..d99f283 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/AccessLimitUtils.java @@ -0,0 +1,41 @@ +package com.mixi.common.utils; + +import com.mixi.common.config.exception.BusinessException; +import lombok.extern.slf4j.Slf4j; + +/** + * 流量访问限制工具类 + */ +@Slf4j +public class AccessLimitUtils { + + /** + * 校验是否超过指定流量限制 + * + * @param interfaceName + * @return + */ + public static void validate(String interfaceName, Integer count) { + Integer useCount = LocalCacheUtils.getAidaInterfaceCurrentLimitingCache(interfaceName); + if (useCount > count) { + //系统繁忙 + throw new BusinessException("system busy !"); + } else { + useCount++; + LocalCacheUtils.setAidaInterfaceCurrentLimitingCache(interfaceName, useCount); + } + } + + /** + * 校验过后 接口完毕 去掉限流 + * + * @param interfaceName + * @return + */ + public static void validateOut(String interfaceName) { + Integer useCount = LocalCacheUtils.getAidaInterfaceCurrentLimitingCache(interfaceName); + useCount--; + LocalCacheUtils.setAidaInterfaceCurrentLimitingCache(interfaceName, useCount); + } + +} diff --git a/src/main/java/com/mixi/common/utils/CloseUtil.java b/src/main/java/com/mixi/common/utils/CloseUtil.java new file mode 100644 index 0000000..b6a4502 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/CloseUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mixi.common.utils; + +import java.io.Closeable; + +/** + * @author Zheng Jie + * @website https://el-admin.vip + * @description 用于关闭各种连接,缺啥补啥 + * @date 2021-03-05 + **/ +public class CloseUtil { + + public static void close(Closeable closeable) { + if (null != closeable) { + try { + closeable.close(); + } catch (Exception e) { + // 静默关闭 + } + } + } + + public static void close(AutoCloseable closeable) { + if (null != closeable) { + try { + closeable.close(); + } catch (Exception e) { + // 静默关闭 + } + } + } +} diff --git a/src/main/java/com/mixi/common/utils/ConvertUtil.java b/src/main/java/com/mixi/common/utils/ConvertUtil.java new file mode 100644 index 0000000..0a02b1a --- /dev/null +++ b/src/main/java/com/mixi/common/utils/ConvertUtil.java @@ -0,0 +1,68 @@ +package com.mixi.common.utils; + +import cn.hutool.core.util.StrUtil; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author: dangweijian + * @description: 驼峰下划线处理工具 + * @create: 2020-01-02 22:33 + **/ +public class ConvertUtil { + + private static Pattern linePattern = Pattern.compile("_(\\w)"); + + /** + * 下划线转驼峰 + */ + public static String lineToHump(String str) { + str = str.toLowerCase(); + Matcher matcher = linePattern.matcher(str); + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, matcher.group(1).toUpperCase()); + + } + matcher.appendTail(sb); + return sb.toString(); + + } + + /** + * 驼峰转下划线(简单写法,效率低于{@link #humpToLine2(String)}) + */ + public static String humpToLine(String str) { + return str.replaceAll("[A-Z]", "_$0").toLowerCase(); + + } + + + private static Pattern humpPattern = Pattern.compile("[A-Z]"); + + /** + * 驼峰转下划线,效率比上面高 + */ + public static String humpToLine2(String str) { + Matcher matcher = humpPattern.matcher(str); + StringBuffer sb = new StringBuffer(); + while (matcher.find()) { + matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase()); + } + matcher.appendTail(sb); + return sb.toString(); + } + + public static String lowerCaseFirstLetter(String str){ + if(StrUtil.isNotBlank(str)){ + str = str.trim(); + String result = str.substring(0, 1).toLowerCase(); + if(str.length() > 1){ + result += str.substring(1); + } + return result; + } + return null; + } +} diff --git a/src/main/java/com/mixi/common/utils/CopyUtil.java b/src/main/java/com/mixi/common/utils/CopyUtil.java new file mode 100644 index 0000000..b7d4ccb --- /dev/null +++ b/src/main/java/com/mixi/common/utils/CopyUtil.java @@ -0,0 +1,127 @@ +package com.mixi.common.utils; + +import org.apache.logging.log4j.util.BiConsumer; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CopyUtil { + + public static T copyObject(Object source, Class tClass) throws BeansException { + return entityToModel(source, tClass); + } + + public static List copyList(List source, Class tClass) { + if (source == null || source.isEmpty()) { + return new ArrayList<>(); + } + List tList = new ArrayList<>(); + for (F f : source) { + T t = entityToModel(f, tClass); + tList.add(t); + } + return tList; + } + + public static List copyList(List source, Class tClass, BiConsumer consumer) { + if (source == null || source.isEmpty()) { + return new ArrayList<>(); + } + List tList = new ArrayList<>(); + for (F f : source) { + T t = entityToModel(f, tClass); + consumer.accept(f, t); + tList.add(t); + } + return tList; + } + + public static List copyListToString(List source, String fieldName) { + + List list = new ArrayList<>(); + if (null == source || source.isEmpty()) { + return list; + } + + for (int i = 0; i < source.size(); i++) { + try { + Class c = source.get(i).getClass(); + if (null != c) { + Method methodGetKey = c.getMethod(fieldName); + String key = "" + methodGetKey.invoke(source.get(i)); + list.add(key); + } + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + return list; + } + + /** + * 复制对象 + * + * @param entity + * @param modelClass + * @param + * @param + * @return + */ + private static T entityToModel(F entity, Class modelClass) { + Object model = null; + if (entity == null || modelClass == null) { + return null; + } + try { + model = modelClass.newInstance(); + } catch (Exception e) { + //忽略 + } + BeanUtils.copyProperties(entity, model); + return (T) model; + } + + public static Map listToMap(List list, Class c) { + List vList = CopyUtil.copyList(list, c); + return list2Map(vList, c); + } + + public static Map listToMap(List list, Class c, String fieldName) { + List vList = CopyUtil.copyList(list, c); + return list2Map(vList, c, fieldName); + } + + public static Map list2Map(List list, Class c) { + return list2Map(list, c, "getId"); + } + + + public static Map list2Map(List list, Class c, String fieldName) { + Map map = new HashMap<>(); + if (list != null) { + try { + Method methodGetKey = c.getMethod(fieldName); + for (int i = 0; i < list.size(); i++) { + V value = list.get(i); + @SuppressWarnings("unchecked") + K key = (K) methodGetKey.invoke(list.get(i)); + map.put(key, value); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return map; + } + +} diff --git a/src/main/java/com/mixi/common/utils/DateUtil.java b/src/main/java/com/mixi/common/utils/DateUtil.java new file mode 100644 index 0000000..7144c7f --- /dev/null +++ b/src/main/java/com/mixi/common/utils/DateUtil.java @@ -0,0 +1,65 @@ +package com.mixi.common.utils; + +import lombok.extern.slf4j.Slf4j; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.TimeZone; + +@Slf4j +public class DateUtil { + public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + public static final String YYYYMM = "yyyyMM"; + public static final String YYYY_MM_DD = "yyyyMMdd"; + /** + * LocalDate -> Date + */ + public static Date asDate(LocalDate localDate) { + return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()); + } + + /** + * LocalDateTime -> Date + */ + public static Date asDate(LocalDateTime localDateTime) { + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } + /** + * date 装 String + * @param date + * @param formatter + * @return + */ + public static String dateToStr(Date date, String formatter) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatter); + Instant instant = date.toInstant(); + ZoneId zoneId = ZoneId.systemDefault(); + LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId); + return dateTimeFormatter.format(localDateTime); + } + /** + * 根据时区获取时间 + * @param timeZone "Asia/Tokyo" + * @return + */ + public static Date getByTimeZone(String timeZone) { + String dateStr = dateToStr(new Date(),YYYY_MM_DD_HH_MM_SS); + SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS); + // 设置时区 + sdf.setTimeZone(TimeZone.getTimeZone(timeZone)); + Date date = null; + try{ + date = sdf.parse(dateStr); + }catch (ParseException parseException){ + log.error("时间转换异常!",parseException); + } + return date; + } + +} diff --git a/src/main/java/com/mixi/common/utils/FileUtil.java b/src/main/java/com/mixi/common/utils/FileUtil.java new file mode 100644 index 0000000..7c32c19 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/FileUtil.java @@ -0,0 +1,266 @@ +package com.mixi.common.utils; + +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.StrUtil; +import com.mixi.common.config.exception.BusinessException; +import com.mixi.model.vo.FileVO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.URL; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +public class FileUtil extends cn.hutool.core.io.FileUtil { + + private static final Logger log = LoggerFactory.getLogger(FileUtil.class); + + /** + * 系统临时目录 + *
+ * windows 包含路径分割符,但Linux 不包含, + * 在windows \\==\ 前提下, + * 为安全起见 同意拼装 路径分割符, + *
+     *       java.io.tmpdir
+     *       windows : C:\Users/xxx\AppData\Local\Temp\
+     *       linux: /temp
+     * 
+ */ + public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator; + /** + * 定义GB的计算常量 + */ + private static final int GB = 1024 * 1024 * 1024; + /** + * 定义MB的计算常量 + */ + private static final int MB = 1024 * 1024; + /** + * 定义KB的计算常量 + */ + private static final int KB = 1024; + + /** + * 格式化小数 + */ + private static final DecimalFormat DF = new DecimalFormat("0.00"); + + public static final String IMAGE = "图片"; + public static final String TXT = "文档"; + public static final String MUSIC = "音乐"; + public static final String VIDEO = "视频"; + public static final String OTHER = "其他"; + + + /** + * MultipartFile转File + */ + public static File toFile(MultipartFile multipartFile) { + // 获取文件名 + String fileName = multipartFile.getOriginalFilename(); + // 获取文件后缀 + String prefix = "." + getExtensionName(fileName); + File file = null; + try { + // 用uuid作为文件名,防止生成的临时文件重复 + file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix); + // MultipartFile to File + multipartFile.transferTo(file); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + return file; + } + +// public static void main(String[] args) { +// File file = new File( +// "http://18.162.111.141:5568/download/202211/userFile/collection/Printboard/1/a3c9838c-2171-44d7-af54-c94ee6affcd9print_2.jpg.png"); +// FileUtil.getFileSize() +// } + + /** + * 获取文件扩展名,不带 . + */ + public static String getExtensionName(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length() - 1))) { + return filename.substring(dot + 1); + } + } + return filename; + } + + + /** + * inputStream 转 File + */ + static File inputStreamToFile(InputStream ins, String name) { + File file = new File(SYS_TEM_DIR + name); + if (file.exists()) { + return file; + } + OutputStream os = null; + try { + os = new FileOutputStream(file); + int bytesRead; + int len = 8192; + byte[] buffer = new byte[len]; + while ((bytesRead = ins.read(buffer, 0, len)) != -1) { + os.write(buffer, 0, bytesRead); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + CloseUtil.close(os); + CloseUtil.close(ins); + } + return file; + } + + /** + * 获取文件尺寸 + */ + public static FileVO getFileSize(MultipartFile file) { + int width = 0; + int height = 0; + try{ + // 图片对象 + BufferedImage bufferedImage = ImageIO.read(file.getInputStream()); + // 宽度 + width = bufferedImage.getWidth(); + // 高度 + height = bufferedImage.getHeight(); + }catch (IOException ioException){ + log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException)); + } + return new FileVO(height,width); + } + /** + * 获取文件尺寸 + */ + public static FileVO getFileSize(InputStream inputStream) { + int width = 0; + int height = 0; + try{ + // 图片对象 + BufferedImage bufferedImage = ImageIO.read(inputStream); + // 宽度 + width = bufferedImage.getWidth(); + // 高度 + height = bufferedImage.getHeight(); + }catch (IOException ioException){ + log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException)); + } + return new FileVO(height,width); + } + /** + * 获取远程文件流 + */ + public static InputStream getOriginFile(String path) { + + try{ + //远程 + URL url = new URL(path); + return url.openStream(); + }catch (IOException ioException){ + log.error("获取文件尺寸异常###{}###path##{}", ExceptionUtil.stacktraceToString(ioException),path); + throw new BusinessException("get file is failed!"); + } + } + /** + * 将文件名解析成文件的上传路径 + */ + public static File upload(MultipartFile file, String filePath) { + Date date = new Date(); + SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS"); + String suffix = getExtensionName(file.getOriginalFilename()); + String nowStr = format.format(date)+"-" ; + try { + String fileName = file.getOriginalFilename(); + String path = filePath + fileName; + // getCanonicalFile 可解析正确各种路径 + File dest = new File(path).getCanonicalFile(); + // 检测是否存在目录 + if (!dest.getParentFile().exists()) { + if (!dest.getParentFile().mkdirs()) { + System.out.println("was not successful."); + } + } + // 文件写入 + file.transferTo(dest); + return dest; + } catch (Exception e) { + log.error(e.getMessage(), e); + } + return null; + } + /** + * 删除文件 + */ + public static boolean delete(String path) { + File file = new File(path); + if (file.exists()) { + return file.delete(); + } + return false; + } + /** + * 获取指定文件夹下所有文件,不含文件夹里的文件 + * + * @param dirFilePath 文件夹路径 + * @return + */ + public static List getAllFile(String dirFilePath) { + if (StrUtil.isBlank(dirFilePath)){ + return null; + } + return getAllFile(new File(dirFilePath)); + } + + /** + * 获取指定文件夹下所有文件,不含文件夹里的文件 + * + * @param dirFile 文件夹 + * @return + */ + public static List getAllFile(File dirFile) { + // 如果文件夹不存在或着不是文件夹,则返回 null + if (Objects.isNull(dirFile) || !dirFile.exists() || dirFile.isFile()){ + return null; + } + File[] childrenFiles = dirFile.listFiles(); + if (Objects.isNull(childrenFiles) || childrenFiles.length == 0){ + return null; + } + List files = new ArrayList<>(); + for (File childFile : childrenFiles) { + // 如果是文件,直接添加到结果集合 + if (childFile.isFile()) { + files.add(childFile); + } + //以下几行代码取消注释后可以将所有子文件夹里的文件也获取到列表里 + else { + // 如果是文件夹,则将其内部文件添加进结果集合 + List cFiles = getAllFile(childFile); + if (Objects.isNull(cFiles) || cFiles.isEmpty()){ + continue; + } + files.addAll(cFiles); + } + } + return files; + } + + +} diff --git a/src/main/java/com/mixi/common/utils/JSONResponseUtils.java b/src/main/java/com/mixi/common/utils/JSONResponseUtils.java new file mode 100644 index 0000000..4fbf6a9 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/JSONResponseUtils.java @@ -0,0 +1,42 @@ +package com.mixi.common.utils; + +import com.alibaba.fastjson.JSON; +import com.mixi.common.response.Response; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.ServletResponse; +import java.io.PrintWriter; + + +/** + * @author: dangweijian + * @description: 构造JSON响应工具类 + * @Author dwjian + * @Date 2020/7/10 15:51 + **/ +@Slf4j +public class JSONResponseUtils { + + /** + * 使用response输出JSON + * + * @param servletResponse + * @param response + */ + public static void build(ServletResponse servletResponse, Response response) { + PrintWriter out = null; + try { + servletResponse.setCharacterEncoding("UTF-8"); + servletResponse.setContentType("application/json"); + out = servletResponse.getWriter(); + out.println(JSON.toJSONString(response)); + } catch (Exception e) { + log.error(e + "输出JSON出错"); + } finally { + if (out != null) { + out.flush(); + out.close(); + } + } + } +} diff --git a/src/main/java/com/mixi/common/utils/LocalCacheUtils.java b/src/main/java/com/mixi/common/utils/LocalCacheUtils.java new file mode 100644 index 0000000..df5bfd1 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/LocalCacheUtils.java @@ -0,0 +1,277 @@ +package com.mixi.common.utils; + +import com.google.common.cache.*; +import com.mixi.model.dto.ProductProcessDTO; +import lombok.extern.slf4j.Slf4j; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +/** + * @author: yanglei + * @description: 本地缓存工具 + * @create: 2022-08-11 9:23 + **/ +@Slf4j +public final class LocalCacheUtils { + /** + * token + */ + private static LoadingCache tokenCache = loadTokenCache(); + /** + * 邮箱,短信验证码 + */ + private static LoadingCache emailCache = CacheBuilder.newBuilder() + //设置并发级别为5,并发级别是指可以同时写缓存的线程数 + .concurrencyLevel(5) + //设置写缓存后一分钟过期 + .expireAfterWrite(60, TimeUnit.SECONDS) + //刷新机制 每隔一定时间刷新缓存loader 只有调用get具体的操作才生效(懒加载) 不设置则不刷新 +// .refreshAfterWrite(60, TimeUnit.SECONDS) + //设置缓存容器的初始容量为100 + .initialCapacity(100) + //设置缓存最大容量10000,超过100之后就会按照LRU最近虽少使用算法来移除缓存项 + .maximumSize(10000) + //设置要统计缓存的命中率 + .recordStats() + //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存 + .build(new CacheLoader() { + @Override + public String load(String key) throws Exception { + return RandomsUtil.generateVerifyCode(1000L,9999L); + } + });; + + /** + * + *缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时可以自动加载缓存 + */ + private static LoadingCache loadTokenCache(){ + LoadingCache tokenCache = CacheBuilder.newBuilder() + .concurrencyLevel(20) + .expireAfterWrite(24*100, TimeUnit.HOURS) + .initialCapacity(100) + .maximumSize(10000) + .recordStats() + .build(new CacheLoader() { + @Override + public String load(String key) throws Exception { + return "null"; + } + }); + return tokenCache; + } + + /** + * aida 接口限流(先粗暴做) + */ + private static LoadingCache aidaInterfaceCurrentLimiting = CacheBuilder.newBuilder() + //设置并发级别为5,并发级别是指可以同时写缓存的线程数 + .concurrencyLevel(20) + //设置写缓存后30天过期 + .expireAfterWrite(60*60*24*30, TimeUnit.SECONDS) + //设置缓存容器的初始容量为100 + .initialCapacity(5) + //设置缓存最大容量50000,超过50000之后就会按照LRU最近虽少使用算法来移除缓存项 + .maximumSize(20) + //设置要统计缓存的命中率 + .recordStats() + //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存 + .build(new CacheLoader() { + @Override + public Integer load(String key) throws Exception { + return 0; + } + }); + + /** + * 商品文件进度统计 + */ + private static LoadingCache productProcessCache = CacheBuilder.newBuilder() + //设置并发级别为10,并发级别是指可以同时写缓存的线程数 + .concurrencyLevel(1000) + //设置写缓存后5分钟过期 + .expireAfterWrite(60*30, TimeUnit.SECONDS) + //设置缓存容器的初始容量为100 + .initialCapacity(5) + //设置缓存最大容量50000,超过50000之后就会按照LRU最近虽少使用算法来移除缓存项 + .maximumSize(100) + //设置要统计缓存的命中率 + .recordStats() + //build方法中可以指定CacheLoader,在缓存不存在时通过CacheLoader的实现自动加载缓存 + .build(new CacheLoader() { + @Override + public ProductProcessDTO load(Long key) throws Exception { + return new ProductProcessDTO(0,0,"Attribute",0); + } + }); + /** + * 添加token本地缓存 + * @param key + * @param value + */ + public static void setTokenCache(String key, String value) { + tokenCache.put(key, value); + } + + /** + * 获取token本地缓存 + * @param key + * @return + */ + public static String getTokenCache(String key) { + try { + String value = tokenCache.get(key); + if ("null".equals(value)) { + return null; + } + return value; + } catch (ExecutionException e) { + log.error("getTokenCache方法错误", e); + } + return null; + } + /** + * 获取token本地缓存 + * @param key + * @return + */ + public static void clearTokenCache(String key) { + try { + tokenCache.invalidate(key); + } catch (Exception e) { + log.error("clearTokenCache方法错误", e); + } + } + + /** + * 设置本次接口流量数 + * @param key + * @param value + */ + public static void setAidaInterfaceCurrentLimitingCache(String key, Integer value) { + aidaInterfaceCurrentLimiting.put(key, value); + } + + /** + * 获取本次接口流量数 + * @param key + * @return + */ + public static Integer getAidaInterfaceCurrentLimitingCache(String key) { + try { + return aidaInterfaceCurrentLimiting.get(key); + } catch (ExecutionException e) { + log.error("getAidaInterfaceCurrentLimitingCache方法错误", e); + } + return null; + } + /** + * 添加token本地缓存 + * @param key + * @param value + */ + public static void setEmailCache(String key, String value) { + emailCache.put(key, value); + } + + /** + * 获取验证码本地缓存 + * @param key + * @return + */ + public static String getVerifyCodeCache(String key) { + try { + String value = emailCache.get(key); + if ("null".equals(value)) { + return null; + } + return value; + } catch (ExecutionException e) { + log.error("getTokenCache方法错误", e); + } + return null; + } + + /** + * 添加商品文件进度统计 + * @param key + * @param productProcess + */ + public static void setProductUploadProcessCache(Long key, ProductProcessDTO productProcess) { + productProcessCache.put(key, productProcess); + } + + /** + * 获取商品文件进度统计 + * @param key + * @return + */ + public static ProductProcessDTO getProductUploadProcessCache(Long key) { + try { + return productProcessCache.get(key); + } catch (ExecutionException e) { + log.error("getProductUploadProcessCache方法错误", e); + } + return null; + } + /** + * 进度统计完后 删除进度 + * @param key + * @return + */ + public static void delProductUploadProcessCache(Long key) { + try { + productProcessCache.invalidate(key); + } catch (Exception e) { + log.error("delProductUploadProcessCache方法错误", e); + } + } + + /** + * 预签名URL缓存 + */ + private static LoadingCache presignedUrlCache = CacheBuilder.newBuilder() + .concurrencyLevel(10) + .expireAfterWrite((24 * 60 - 1), TimeUnit.MINUTES) + .initialCapacity(100) + .maximumSize(10000) + .recordStats() + .build(new CacheLoader() { + @Override + public String load(String key) throws Exception { + return "null"; + } + }); + + /** + * 添加预签名URL到缓存 + * + * @param key URL的唯一标识 + * @param value 预签名URL + */ + public static void setPresignedUrlCache(String key, String value) { + presignedUrlCache.put(key, value); + } + + /** + * 获取预签名URL + * + * @param key URL的唯一标识 + * @return 预签名URL,如果不存在则返回null + */ + public static String getPresignedUrlCache(String key) { + try { + String value = presignedUrlCache.get(key); + if ("null".equals(value)) { + return null; + } + return value; + } catch (ExecutionException e) { + log.error("getPresignedUrlCache方法错误", e); + } + return null; + } +} diff --git a/src/main/java/com/mixi/common/utils/MD5Utils.java b/src/main/java/com/mixi/common/utils/MD5Utils.java new file mode 100644 index 0000000..96ebbb7 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/MD5Utils.java @@ -0,0 +1,116 @@ +package com.mixi.common.utils; + +import cn.hutool.core.exceptions.ExceptionUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.DigestUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.io.*; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * MD5加密工具 + */ +@Slf4j +public class MD5Utils { + + /** + * MD5加密 + * + * @param str + * @return + */ + public static String encrypt(String str) { + byte[] mdBytes = null; + try { + mdBytes = MessageDigest.getInstance("MD5").digest( + str.getBytes()); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5算法不存在!"); + } + String mdCode = new BigInteger(1, mdBytes).toString(16); + + if (mdCode.length() < 32) { + int a = 32 - mdCode.length(); + for (int i = 0; i < a; i++) { + mdCode = "0" + mdCode; + } + } + // 默认返回32位小写 + return mdCode; + } + + /** + * MD5加密文件 + * + * @param file + * @return + */ + public static String encryptFile(MultipartFile file) { + String md5 = null; + try { + md5 = DigestUtils.md5DigestAsHex(file.getInputStream()); + } catch (IOException ioException) { + log.error("文件MultipartFile md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException)); + } + return md5; + } + /** + * MD5加密文件 + * + * @param inputStream + * @return + */ + public static String encryptFile(FileInputStream inputStream) { + String md5 = null; + try { + md5 = DigestUtils.md5DigestAsHex(inputStream); + } catch (IOException ioException) { + log.error("文件MultipartFile md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException)); + } + return md5; + } + + public static void main(String[] args) throws FileNotFoundException, IOException { + File file1 = new File("/Users/yanglei/Documents/阳磊日报2019-04-23.numbers"); + File file2 = new File("/Users/yanglei/Documents/7777.numbers"); + FileInputStream fileInputStream1 = new FileInputStream(file1); + FileInputStream fileInputStream2 = new FileInputStream(file2); + String md51 = DigestUtils.md5DigestAsHex(fileInputStream1); + String md52 = DigestUtils.md5DigestAsHex(fileInputStream2); + if (md51.equals(md52)) { + System.out.println(md51); + } + System.out.println("md51==" + md51); + System.out.println("md52==" + md52); + + } + + + /** + * MD5加密文件 + * + * @param path + * @return + */ + public static String encryptFile(String path, Boolean isLocal) { + String md5 = null; + try { + InputStream inputStream = null; + if (isLocal) { + File file = new File(path); + inputStream = new FileInputStream(file); + } else { + //远程 + inputStream = FileUtil.getOriginFile(path); + } + md5 = DigestUtils.md5DigestAsHex(inputStream); + } catch (IOException ioException) { + log.error("文件File md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException)); + } + return md5; + } + +} diff --git a/src/main/java/com/mixi/common/utils/MinioUtil.java b/src/main/java/com/mixi/common/utils/MinioUtil.java new file mode 100644 index 0000000..2095ffb --- /dev/null +++ b/src/main/java/com/mixi/common/utils/MinioUtil.java @@ -0,0 +1,419 @@ +package com.mixi.common.utils; + +import com.mixi.common.config.exception.BusinessException; +import io.minio.*; +import io.minio.errors.MinioException; +import io.minio.http.Method; +import io.minio.messages.DeleteError; +import io.minio.messages.DeleteObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * @description: minio工具类 + * @version:3.0 + */ +@Component +public class MinioUtil { + @Autowired + private MinioClient minioClient; + + /** + * description: 判断bucket是否存在,不存在则创建 + * + * @return: void + */ + public void existBucket(String name) { + try { + boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build()); + if (!exists) { + minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 创建存储bucket + * + * @param bucketName 存储bucket名称 + * @return Boolean + */ + public Boolean makeBucket(String bucketName) { + try { + minioClient.makeBucket(MakeBucketArgs.builder() + .bucket(bucketName) + .build()); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * 删除存储bucket + * + * @param bucketName 存储bucket名称 + * @return Boolean + */ + public Boolean removeBucket(String bucketName) { + try { + minioClient.removeBucket(RemoveBucketArgs.builder() + .bucket(bucketName) + .build()); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * description: 上传文件 + * + * @param bucketName + * @param path + * @param multipartFile + * @return: java.lang.String + */ + public List uploadBatch(String bucketName, String path, MultipartFile[] multipartFile) { + List names = new ArrayList<>(multipartFile.length); + for (MultipartFile file : multipartFile) { + String fileName = file.getOriginalFilename(); + String[] split = fileName.split("\\."); + if (split.length > 1) { + fileName = path + "/" + UUID.randomUUID() + "." + split[1]; + } else { + fileName = path + "/" + UUID.randomUUID(); + } + InputStream in = null; + try { + in = file.getInputStream(); + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketName) + .object(fileName) + .stream(in, in.available(), -1) + .contentType(file.getContentType()) + .build() + ); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + names.add(fileName); + } + return names; + } + + /** + * description: 上传文件 + * + * @param bucketName + * @param path + * @param file + * @return: java.lang.String + */ + public String upload(String bucketName, String path, MultipartFile file) { + String fileName = file.getOriginalFilename(); +// String[] split = fileName.split("\\."); + fileName = path; + InputStream in = null; + try { + in = file.getInputStream(); + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketName) + .object(fileName) + .stream(in, in.available(), -1) + .contentType(file.getContentType()) + .build() + ); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return bucketName + "/" + fileName; + } + + public String upload(String bucketName, String path, MultipartFile file, String copy) { + InputStream in = null; + try { + in = file.getInputStream(); + minioClient.putObject(PutObjectArgs.builder() + .bucket(bucketName) + .object(path) + .stream(in, in.available(), -1) + .contentType(file.getContentType()) + .build() + ); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return bucketName + "/" + path; + } + +// public String upload(String bucketName, String path, File file) { +// InputStream in = null; +// try { +// in = new FileInputStream(file); +// minioClient.putObject(PutObjectArgs.builder() +// .bucket(bucketName) +// .object(path) +// .stream(in, in.available(), -1) +// .contentType(file.getContentType()) +// .build() +// ); +// } catch (Exception e) { +// e.printStackTrace(); +// } finally { +// if (in != null) { +// try { +// in.close(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// } +// return fileName; +// } + + public InputStream download(String bucketName, String objectName) throws MinioException, IOException { + try { + return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } catch (InvalidKeyException e) { + throw new RuntimeException(e); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + public InputStream download(String path) throws MinioException, IOException { + if (!path.contains("/")) { + throw new BusinessException("the.path.is.error"); + } + int index = path.indexOf("/"); + String bucketName = path.substring(0, index); + String objectName = path.substring(index + 1); + return download(bucketName, objectName); + } + + /** + * description: 下载文件 + * + * @param path + * @param bucketName + * @return: org.springframework.http.ResponseEntity + */ +// public ResponseEntity download(String path, String bucketName) { +// ResponseEntity responseEntity = null; +// InputStream in = null; +// ByteArrayOutputStream out = null; +// try { +// in = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(path).build()); +// out = new ByteArrayOutputStream(); +// IOUtils.copy(in, out); +// //封装返回值 +// byte[] bytes = out.toByteArray(); +// HttpHeaders headers = new HttpHeaders(); +// try { +// headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(path, "UTF-8")); +// } catch (UnsupportedEncodingException e) { +// e.printStackTrace(); +// } +// headers.setContentLength(bytes.length); +// headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); +// headers.setAccessControlExposeHeaders(Arrays.asList("*")); +// responseEntity = new ResponseEntity(bytes, headers, HttpStatus.OK); +// } catch (Exception e) { +// e.printStackTrace(); +// } finally { +// try { +// if (in != null) { +// try { +// in.close(); +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// if (out != null) { +// out.close(); +// } +// } catch (IOException e) { +// e.printStackTrace(); +// } +// } +// return responseEntity; +// } + + /** + * 查看文件对象 + * + * @param bucketName 存储bucket名称 + * @return 存储bucket内文件对象信息 + */ +// public List listObjects(String bucketName) { +// Iterable> results = minioClient.listObjects( +// ListObjectsArgs.builder().bucket(bucketName).build()); +// List objectItems = new ArrayList<>(); +// try { +// for (Result result : results) { +// Item item = result.get(); +// ObjectItem objectItem = new ObjectItem(); +// objectItem.setObjectName(item.objectName()); +// objectItem.setSize(item.size()); +// objectItems.add(objectItem); +// } +// } catch (Exception e) { +// e.printStackTrace(); +// return null; +// } +// return objectItems; +// } + + /** + * 批量删除文件对象 + * + * @param bucketName 存储bucket名称 + * @param objects 对象名称集合 + */ + public Iterable> removeObjects(String bucketName, List objects) { + List dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList()); + Iterable> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build()); + return results; + } + + public void deleteObject(String bucketName, String objectName) { + try { + minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build()); + System.out.println("Object " + objectName + " successfully removed from bucket " + bucketName); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Error while removing object " + objectName + " from bucket " + bucketName + ": " + e.getMessage()); + } + } + + public void deleteObject(String path) { + if (!path.contains("/")) { + throw new BusinessException("The path is error!"); + } + int index = path.indexOf("/"); + String bucketName = path.substring(0, index); + String objectName = path.substring(index + 1); + deleteObject(bucketName, objectName); + } + + /** + * 获取文件的临时URL + * + * @param bucketName 存储桶名称 + * @param fileName 文件名 + * @param expiry 过期时间(单位:分) + * @return 文件的临时URL,如果出现异常则返回null + */ + public String getPresignedUrl(String bucketName, String fileName, int expiry) { + try { + return minioClient.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .bucket(bucketName) + .object(fileName) + .expiry(expiry, TimeUnit.MINUTES) + .method(Method.GET) + .build() + ); + } catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new BusinessException(e.getMessage()); + } + } + + public String getPresignedUrl(String path, int expiry) { + if (LocalCacheUtils.getPresignedUrlCache(path) != null) { + return LocalCacheUtils.getPresignedUrlCache(path); + } else { + if (!path.contains("/")) { + throw new BusinessException("The path is error!"); + } + int index = path.indexOf("/"); + String bucketName = path.substring(0, index); + String fileName = path.substring(index + 1); + String presignedUrl = getPresignedUrl(bucketName, fileName, expiry); + LocalCacheUtils.setPresignedUrlCache(path, presignedUrl); + return presignedUrl; + } + } + + /** + * 将桶名、文件名从url中分离出来 + * + * @param url 带桶名、文件名的url + * @param expiry 图片过期时间 + * @return 可以直接访问的minio图片地址 + */ + public String splitThenGetPreviewUrl(String url, int expiry) { + String[] parts = url.split("/"); + String bucketName = parts[0]; + StringBuilder fileName = new StringBuilder(); + for (int i = 1; i < parts.length; i++) { + fileName.append(parts[i]); + if (i != parts.length - 1) { + fileName.append("/"); + } + } + return getPresignedUrl(bucketName, String.valueOf(fileName), expiry); + } + + public boolean doesObjectExist(String bucketName, String objectName) { + try { + minioClient.statObject( + StatObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .build() + ); + return true; + } catch (Exception e) { + // 如果发生异常,说明文件不存在或者出现了其他错误 + return false; + } + } + + public String getMinioPath(Long accountId, String itemGroup, String subGroup, String originalFilename) { + return accountId + "/" + itemGroup+ "/" + subGroup+ "/" + originalFilename; + } +} + + diff --git a/src/main/java/com/mixi/common/utils/MultiReadHttpServletRequest.java b/src/main/java/com/mixi/common/utils/MultiReadHttpServletRequest.java new file mode 100644 index 0000000..9db87cd --- /dev/null +++ b/src/main/java/com/mixi/common/utils/MultiReadHttpServletRequest.java @@ -0,0 +1,170 @@ +package com.mixi.common.utils; + +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * 多次读写BODY用HTTP REQUEST - 解决流只能读一次问题 + */ +@Slf4j +public class MultiReadHttpServletRequest extends HttpServletRequestWrapper { + + private final byte[] body; + + public MultiReadHttpServletRequest(HttpServletRequest request) { + super(request); + String sessionStream = getBodyString(request); + body = sessionStream.getBytes(StandardCharsets.UTF_8); + } + + /** + * 获取请求Body + * + * @param request 请求 + * @return Body字符串 + */ + private String getBodyString(final ServletRequest request) { + StringBuilder sb = new StringBuilder(); + InputStream inputStream = null; + BufferedReader reader = null; + try { + inputStream = cloneInputStream(request.getInputStream()); + reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + String line = ""; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + } + catch (IOException e) { + e.printStackTrace(); + } + finally { + if (inputStream != null) { + try { + inputStream.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + if (reader != null) { + try { + reader.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + } + } + return sb.toString(); + } + + /** + * 复制输入流 + * @param inputStream 请求输入流 + * @return 复制出来的输入流 + */ + private InputStream cloneInputStream(ServletInputStream inputStream) { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + try { + while ((len = inputStream.read(buffer)) > -1) { + byteArrayOutputStream.write(buffer, 0, len); + } + byteArrayOutputStream.flush(); + } + catch (IOException e) { + e.printStackTrace(); + } + return new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + } + + @Override + public BufferedReader getReader() { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + @Override + public ServletInputStream getInputStream() { + + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + + return new ServletInputStream() { + + @Override + public int read() { + return bais.read(); + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + }; + } + + /** + * 将前端请求的表单数据转换成json字符串 - 前后端一体的情况下使用 + * + * @param request: + * @return: java.lang.String + */ + public static String getBodyJsonStrByForm(ServletRequest request) { + Map bodyMap = new HashMap<>(16); + try { + // 参数定义 + String paraName = null; + // 获取请求参数并转换 + Enumeration e = request.getParameterNames(); + while (e.hasMoreElements()) { + paraName = e.nextElement(); + bodyMap.put(paraName, request.getParameter(paraName)); + } + } catch (Exception e) { + log.error("请求参数转换错误!", e); + } + return JSONObject.toJSONString(bodyMap); + } + + /** + * 将前端传递的json数据转换成json字符串 - 前后端分离的情况下使用 + * + * @param request: + * @return: java.lang.String + */ + public static String getBodyJsonStrByJson(ServletRequest request) { + StringBuffer json = new StringBuffer(); + String line; + try { + BufferedReader reader = request.getReader(); + while ((line = reader.readLine()) != null) { + json.append(line); + } + } catch (Exception e) { + log.error("请求参数转换错误!", e); + } + return json.toString(); + } + +} diff --git a/src/main/java/com/mixi/common/utils/MultiReadHttpServletResponse.java b/src/main/java/com/mixi/common/utils/MultiReadHttpServletResponse.java new file mode 100644 index 0000000..fb4389e --- /dev/null +++ b/src/main/java/com/mixi/common/utils/MultiReadHttpServletResponse.java @@ -0,0 +1,77 @@ +package com.mixi.common.utils; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import javax.servlet.ServletOutputStream; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; + +/** + * 多次读写BODY用HTTP RESPONSE - 解决流只能读一次问题 + */ +public class MultiReadHttpServletResponse extends HttpServletResponseWrapper { + + private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + private HttpServletResponse response; + + public MultiReadHttpServletResponse(HttpServletResponse response) { + super(response); + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/json"); + this.response = response; + } + + public byte[] getBody() { + return byteArrayOutputStream.toByteArray(); + } + + @Override + public ServletOutputStream getOutputStream() { + return new ServletOutputStreamWrapper(this.byteArrayOutputStream, this.response); + } + + @Override + public PrintWriter getWriter() throws IOException { + return new PrintWriter(new OutputStreamWriter(getOutputStream(), this.response.getCharacterEncoding())); + } + + + @Data + @AllArgsConstructor + private static class ServletOutputStreamWrapper extends ServletOutputStream { + + private ByteArrayOutputStream outputStream; + private HttpServletResponse response; + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener listener) { + + } + + @Override + public void write(int b) throws IOException { + this.outputStream.write(b); + } + + @Override + public void flush() throws IOException { + if (!this.response.isCommitted()) { + byte[] body = this.outputStream.toByteArray(); + ServletOutputStream outputStream = this.response.getOutputStream(); + outputStream.write(body); + outputStream.flush(); + } + } + } +} diff --git a/src/main/java/com/mixi/common/utils/ObjectUtils.java b/src/main/java/com/mixi/common/utils/ObjectUtils.java new file mode 100644 index 0000000..1d13531 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/ObjectUtils.java @@ -0,0 +1,34 @@ +package com.mixi.common.utils; +import java.lang.reflect.Field; + +public class ObjectUtils { + + /** + * 判断该对象是否所有属性为空 + * 返回ture表示所有属性为null,返回false表示不是所有属性都是null + */ + public static boolean isAllFieldNull(Object object) { + boolean flag = true; + + Class clazz = object.getClass(); + Field[] fields = clazz.getDeclaredFields(); + + for (Field field : fields) { + //设置属性是可以访问的(私有的也可以) + field.setAccessible(true); + Object value = null; + try { + value = field.get(object); + // 只要有1个属性不为空,那么就不是所有的属性值都为空 + if (value != null) { + flag = false; + break; + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + return flag; + } +} diff --git a/src/main/java/com/mixi/common/utils/RandomsUtil.java b/src/main/java/com/mixi/common/utils/RandomsUtil.java new file mode 100644 index 0000000..1caaf11 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/RandomsUtil.java @@ -0,0 +1,44 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.mixi.common.utils; + +import cn.hutool.core.util.RandomUtil; + +import java.text.DecimalFormat; + +/** + * @author yanglei + * @description 随机数工具类 + * @date 2022-07 + **/ +public class RandomsUtil { + + private static String PREFIX = "ver"; + + + + /** + * 生成验证码 + * + * @param randomStart + * @param randomEnd + */ + public static String generateVerifyCode(Long randomStart, Long randomEnd) { + return String.valueOf(RandomUtil.randomLong(randomStart,randomEnd)); + } + + +} diff --git a/src/main/java/com/mixi/common/utils/RedisCacheUtils.java b/src/main/java/com/mixi/common/utils/RedisCacheUtils.java new file mode 100644 index 0000000..af4cfcc --- /dev/null +++ b/src/main/java/com/mixi/common/utils/RedisCacheUtils.java @@ -0,0 +1,50 @@ +package com.mixi.common.utils; + +import cn.hutool.core.util.StrUtil; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @author: dangweijian + * @description: redis缓存工具 + * @create: 2021-01-08 9:23 + **/ +public final class RedisCacheUtils { + + private static RedisTemplate getRedisTemplate(){ + return SpringUtils.getBean("redisTemplate"); + } + + private static RedisTemplate getRedisTemplate(Class clazz){ + return SpringUtils.getBean("redisTemplate"); + } + + private static RedisTemplate> getListRedisTemplate(Class clazz){ + return SpringUtils.getBean("redisTemplate"); + } + + public static T get(String key, Class clazz){ + return getRedisTemplate(clazz).opsForValue().get(key); + } + + public static List getList(String key, Class clazz){ + return getListRedisTemplate(clazz).opsForValue().get(key); + } + + public static void set(String key, Object value){ + getRedisTemplate().opsForValue().set(key, value); + } + + public static void set(String key, Object value, long time, TimeUnit unit){ + getRedisTemplate().opsForValue().set(key, value, time, unit); + } + + public static boolean delete(String key){ + if(StrUtil.isNotEmpty(key)){ + return Boolean.TRUE.equals(getRedisTemplate().delete(key)); + } + return false; + } +} diff --git a/src/main/java/com/mixi/common/utils/RsaDecryptUtils.java b/src/main/java/com/mixi/common/utils/RsaDecryptUtils.java new file mode 100644 index 0000000..ffbb88c --- /dev/null +++ b/src/main/java/com/mixi/common/utils/RsaDecryptUtils.java @@ -0,0 +1,70 @@ +package com.mixi.common.utils; + +import lombok.extern.slf4j.Slf4j; +import org.apache.tomcat.util.codec.binary.Base64; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; + +/** + * Rsa解密工具 + */ +@Slf4j +public class RsaDecryptUtils { + + public static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJA0JB/XhdVz/rxlt/XI8LmB7WvPhT1ZpoLXaMfg7zNN+jRWOpuYc+NDr17uA07yl9h2FHOZ6aG5eoobyUP13gAopQuS7BJYwrrA0HLJjZuROWPw/djA8uxQQ97q22k7evlnZ4a1mVJRONbzQxUKQEgLM0S7+l699/NIZGyI4+XPAgMBAAECgYBlyjh5tZPGIbP93rtlJqst91XVVU4TCVZtY4qWFOQkTfXAveFu9cVP9fYzx0TUlI+0/1zeYRW20At8s7J1Y3eJhurZTLns+GpbFD2qExZVL9w5hqmn9fvOE4jCP7uTlTzVgT9zDxAvCid8mSVHz4z7MWG3/zrJloWQzE2riqeeyQJBAOiqfE4M5dQPopFKGhJBBWdKYLAK+trfi4iqstMfdndCiExGd0Nlw9/RS21LXZFk7RwCood6Q/XyKyXTZMwbTHUCQQCeqnTXhEhYlnRIHOuGKYGVHEFMrIGhPH0LZ7ZQUBp+q0wzUsCY79D9ppIwJPHggDsyJOZatm5eMtHb0dDEqbCzAkEAmHF72LfirjtATOm8g1FO9Qpqp23KRzZI+la9rE7lE+bn3vIcmnBHEpLTVN0YhXcXVE71psaZWMA/PR1w4brRMQJADJvPHTFN7nxGUVS7ArZZrdfI+KbcxktgRH/BZTB4aoiCTbHNzFmCaiXKiDjnX8fQ7HMyOxM0QhgXxTgvNvGlMQJATbRaCq7Ytw1SpHRuRbThjwkKVuinSX9y8rRhof7vEKTYomhoDoH7ZITWq421kXT81mj66ahtkPBccw1NeOqYCg=="; + + public static String decrypt(String content, String privateKey) { + byte[] result; + try { + PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKeyText = keyFactory.generatePrivate(pkcs8EncodedKeySpec5); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, privateKeyText); + result = doLongerCipherFinal(cipher, Base64.decodeBase64(content)); + } catch (Exception e) { + log.error("RSA解密失败", e); + return null; + } + return new String(result); + } + + private static byte[] doLongerCipherFinal(Cipher cipher, byte[] source) throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(cipher.doFinal(source)); + out.close(); + return out.toByteArray(); + } + + /** + * 构建RSA密钥对 + * @param args + */ +// public static void main(String[] args) throws NoSuchAlgorithmException { +// KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); +// keyPairGenerator.initialize(1024); +// KeyPair keyPair = keyPairGenerator.generateKeyPair(); +// RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); +// RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); +// String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded()); +// String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded()); +// System.out.println("公钥:" + publicKeyString); +// System.out.println("私钥:" + privateKeyString); +// } + + /** + * 解密 + * @param args + * @throws NoSuchAlgorithmException + */ + public static void main(String[] args) throws Exception { + String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJA0JB/XhdVz/rxlt/XI8LmB7WvPhT1ZpoLXaMfg7zNN+jRWOpuYc+NDr17uA07yl9h2FHOZ6aG5eoobyUP13gAopQuS7BJYwrrA0HLJjZuROWPw/djA8uxQQ97q22k7evlnZ4a1mVJRONbzQxUKQEgLM0S7+l699/NIZGyI4+XPAgMBAAECgYBlyjh5tZPGIbP93rtlJqst91XVVU4TCVZtY4qWFOQkTfXAveFu9cVP9fYzx0TUlI+0/1zeYRW20At8s7J1Y3eJhurZTLns+GpbFD2qExZVL9w5hqmn9fvOE4jCP7uTlTzVgT9zDxAvCid8mSVHz4z7MWG3/zrJloWQzE2riqeeyQJBAOiqfE4M5dQPopFKGhJBBWdKYLAK+trfi4iqstMfdndCiExGd0Nlw9/RS21LXZFk7RwCood6Q/XyKyXTZMwbTHUCQQCeqnTXhEhYlnRIHOuGKYGVHEFMrIGhPH0LZ7ZQUBp+q0wzUsCY79D9ppIwJPHggDsyJOZatm5eMtHb0dDEqbCzAkEAmHF72LfirjtATOm8g1FO9Qpqp23KRzZI+la9rE7lE+bn3vIcmnBHEpLTVN0YhXcXVE71psaZWMA/PR1w4brRMQJADJvPHTFN7nxGUVS7ArZZrdfI+KbcxktgRH/BZTB4aoiCTbHNzFmCaiXKiDjnX8fQ7HMyOxM0QhgXxTgvNvGlMQJATbRaCq7Ytw1SpHRuRbThjwkKVuinSX9y8rRhof7vEKTYomhoDoH7ZITWq421kXT81mj66ahtkPBccw1NeOqYCg=="; + String decrypt = decrypt("EzAxC/373prww88TXDayIZTvxS3uFAvGhhzLNs+5cOfJU6zm3x/1RA5KcouuWwcYs0bbvNV7zSitLeEGeo23aPUxzr+rsNvCqKHrPNKbcl/oyOFBtOfguVbuHVEy8Q4cpVxfWCd/aEXx9OJXkLEAvlDdDF6SHyKhf+RUmSGEQOg=", privateKey); + System.out.println(decrypt); + } +} diff --git a/src/main/java/com/mixi/common/utils/RsaEncryptUtils.java b/src/main/java/com/mixi/common/utils/RsaEncryptUtils.java new file mode 100644 index 0000000..95f7be5 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/RsaEncryptUtils.java @@ -0,0 +1,46 @@ +package com.mixi.common.utils; + +import org.apache.tomcat.util.codec.binary.Base64; + +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; + +/** + * Rsa加密工具 + */ +public class RsaEncryptUtils { + + /** + * 加密方法 + * + * @param content 需要加密的内容 + * @param publicKey 公钥 + * @return 加密后得到的字符串 + * @throws Exception + */ + public static String encrypt(String content, String publicKey) throws Exception { + X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKey)); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PublicKey publicKeyText = keyFactory.generatePublic(x509EncodedKeySpec2); + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, publicKeyText); + byte[] result = doLongerCipherFinal(cipher, content.getBytes()); + return Base64.encodeBase64String(result); + } + + private static byte[] doLongerCipherFinal(Cipher cipher, byte[] source) throws Exception { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offset = 0; + int totalSize = source.length; + while (totalSize - offset > 0) { + int size = Math.min(cipher.getOutputSize(0) - 11, totalSize - offset); + out.write(cipher.doFinal(source, offset, size)); + offset += size; + } + out.close(); + return out.toByteArray(); + } +} diff --git a/src/main/java/com/mixi/common/utils/SecurityContextUtils.java b/src/main/java/com/mixi/common/utils/SecurityContextUtils.java new file mode 100644 index 0000000..64f4655 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/SecurityContextUtils.java @@ -0,0 +1,32 @@ +package com.mixi.common.utils; + +import com.mixi.model.vo.AuthPrincipalVo; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; + +public class SecurityContextUtils { + + public static AuthPrincipalVo getCurrentUser() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if(authentication != null && authentication.getPrincipal() != null){ + return (AuthPrincipalVo) authentication.getPrincipal(); + } + return null; + } + + public static Long getCurrentUserId() { + AuthPrincipalVo currentUser = getCurrentUser(); + if(currentUser != null){ + return currentUser.getId(); + } + return null; + } + + public static String getCurrentUsername() { + AuthPrincipalVo currentUser = getCurrentUser(); + if(currentUser != null){ + return currentUser.getUsername(); + } + return null; + } +} diff --git a/src/main/java/com/mixi/common/utils/SendEmailUtil.java b/src/main/java/com/mixi/common/utils/SendEmailUtil.java new file mode 100644 index 0000000..335eca6 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/SendEmailUtil.java @@ -0,0 +1,103 @@ +package com.mixi.common.utils; + +import com.alibaba.fastjson.JSONObject; +import com.mixi.common.config.exception.BusinessException; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.ses.v20201002.SesClient; +import com.tencentcloudapi.ses.v20201002.models.SendEmailRequest; +import com.tencentcloudapi.ses.v20201002.models.SendEmailResponse; +import com.tencentcloudapi.ses.v20201002.models.Template; +import lombok.extern.slf4j.Slf4j; + +/** + * 邮件发送类 + */ +@Slf4j +public class SendEmailUtil { + /** + * 秘钥id + */ + private static String SECRET_ID = "AKIDylJaZIkunPkZ7OPAermRovlKccLnysVr"; + /** + * 秘钥key + */ + private static String SECRET_KEy = "5tQgeLlumPmshFVUCdngIcfXeU4NPAdq"; + /** + * 发信地址 + */ + private static String SEND_ADDRESS = "intelligent.curtain@w.mbzn360.com"; + /** + * 登入主题 + */ + public static String LOGIN_SUBJECT = "智能窗帘登入"; + /** + * 忘记密码主题 + */ + public static String FORGET_PWD_SUBJECT = "智能窗帘忘记密码"; + /** + * 注册主题 + */ + public static String REGISTER_SUBJECT = "智能窗帘注册"; + /** + * 登入操作 + */ + public static String LOGIN_OPERATION = "智能窗帘登入操作"; + /** + * 忘记密码操作 + */ + public static String FORGET_PWD_OPERATION = "智能窗帘忘记密码操作"; + /** + * 注册操作 + */ + public static String REGISTER_OPERATION = "智能窗帘注册"; + /** + * 模板id + */ + private static Long TEMPLATE_ID = 34986L; + + + public static Boolean send(String receiverAddress,String subject,String operation,String verifyCode) { + try{ + // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密 + // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取 + Credential cred = new Credential(SECRET_ID, SECRET_KEy); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("ses.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + SesClient client = new SesClient(cred, "ap-hongkong", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendEmailRequest req = new SendEmailRequest(); + + req.setFromEmailAddress(SEND_ADDRESS); + req.setDestination(new String[]{receiverAddress}); + req.setSubject(subject); + req.setTemplate(contractTemplate(operation, verifyCode)); + + // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 + SendEmailResponse resp = client.SendEmail(req); + // 输出json格式的字符串回包 + log.info("短信发送结果res###{}",SendEmailResponse.toJsonString(resp)); + return Boolean.TRUE; + } catch (TencentCloudSDKException e) { + log.info("邮件发送失败###{}",e.toString()); + throw new BusinessException(e.getMessage()); + } + } + private static Template contractTemplate(String operation,String verifyCode){ + Template template = new Template(); + template.setTemplateID(TEMPLATE_ID); + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("operation",operation); + jsonObject.put("code",verifyCode); + template.setTemplateData(jsonObject.toJSONString()); + return template; + } +} diff --git a/src/main/java/com/mixi/common/utils/SendSmsUtil.java b/src/main/java/com/mixi/common/utils/SendSmsUtil.java new file mode 100644 index 0000000..5a4afde --- /dev/null +++ b/src/main/java/com/mixi/common/utils/SendSmsUtil.java @@ -0,0 +1,106 @@ +package com.mixi.common.utils; + +import com.mixi.common.config.exception.BusinessException; +import com.tencentcloudapi.common.Credential; +import com.tencentcloudapi.common.exception.TencentCloudSDKException; +import com.tencentcloudapi.common.profile.ClientProfile; +import com.tencentcloudapi.common.profile.HttpProfile; +import com.tencentcloudapi.sms.v20210111.SmsClient; +import com.tencentcloudapi.sms.v20210111.models.*; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.util.Arrays; + +import java.util.Objects; + +/** + * 短信发送类 + */ +@Slf4j +public class SendSmsUtil { + /** + * 秘钥id + */ + private static String SECRET_ID = "AKIDylJaZIkunPkZ7OPAermRovlKccLnysVr"; + /** + * 秘钥key + */ + private static String SECRET_KEy = "5tQgeLlumPmshFVUCdngIcfXeU4NPAdq"; + /** + * sdkAppId + */ + private static String SDK_APP_ID = "1400722195"; + /** + * 签名 + */ + public static String SIGN_NAME = "深呼吸智能窗帘"; + /** + * 忘记密码模板 + */ + public static String FORGET_TEMPLATE_ID = "1514353"; + /** + * 登入模板 + */ + public static String LOGIN_TEMPLATE_ID = "1514349"; + /** + * 登入操作 + */ + public static String LOGIN_OPERATION = "登入"; + /** + * 忘记密码操作 + */ + public static String FORGET_PWD_OPERATION = "忘记密码操作"; + + + public static Boolean send(String phone, String templateId, String verifyCode) { + try{ + // 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey,此处还需注意密钥对的保密 + // 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取 + Credential cred = new Credential(SECRET_ID, SECRET_KEy); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setReqMethod("POST"); + /* SDK有默认的超时时间,非必要请不要进行调整 + * 如有需要请在代码中查阅以获取最新的默认值 */ + httpProfile.setConnTimeout(60); + /* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */ + httpProfile.setEndpoint("sms.tencentcloudapi.com"); + + /* 非必要步骤: + * 实例化一个客户端配置对象,可以指定超时时间等配置 */ + ClientProfile clientProfile = new ClientProfile(); + /* SDK默认用TC3-HMAC-SHA256进行签名 + * 非必要请不要修改这个字段 */ + clientProfile.setSignMethod("HmacSHA256"); + clientProfile.setHttpProfile(httpProfile); + /* 实例化要请求产品(以sms为例)的client对象 + * 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */ + SmsClient client = new SmsClient(cred, "ap-guangzhou",clientProfile); + + SendSmsRequest req = new SendSmsRequest(); + req.setSmsSdkAppId(SDK_APP_ID); + req.setSignName(SIGN_NAME); + req.setTemplateId(templateId); + //模板参数 + String[] templateParamSet = {verifyCode}; + req.setTemplateParamSet(templateParamSet); + /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号] + * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号 */ + String[] phoneNumberSet = {phone}; + req.setPhoneNumberSet(phoneNumberSet); + //发送短信 + SendSmsResponse res = client.SendSms(req); + log.info("短信发送结果res###{}",SendSmsResponse.toJsonString(res)); + if(Objects.isNull(res)|| Arrays.isNullOrContainsNull(res.getSendStatusSet()) + ||(! res.getSendStatusSet()[0].getCode().equals("Ok")) ){ + SendStatus message = res.getSendStatusSet()[0]; + throw new BusinessException(message.getMessage()); + } + // 输出json格式的字符串回包 + } catch (TencentCloudSDKException e) { + log.error(e.toString()); + return Boolean.FALSE; + } + return Boolean.TRUE; + } + +} diff --git a/src/main/java/com/mixi/common/utils/SpringUtils.java b/src/main/java/com/mixi/common/utils/SpringUtils.java new file mode 100644 index 0000000..8328963 --- /dev/null +++ b/src/main/java/com/mixi/common/utils/SpringUtils.java @@ -0,0 +1,44 @@ +package com.mixi.common.utils; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * @ClassName SpringUtils + * @Description springBean工具 + * @Author dwjian + * @Date 2020/1/15 17:10 + */ +@Component +public class SpringUtils implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + public static T getBean(Class clazz) { + return applicationContext.getBean(clazz); + } + + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + SpringUtils.applicationContext = applicationContext; + } + + public static T getBean(String beanName) { + if(applicationContext.containsBean(beanName)){ + return (T) applicationContext.getBean(beanName); + }else{ + return null; + } + } + + public static Map getBeansOfType(Class baseType){ + return applicationContext.getBeansOfType(baseType); + } + + public static ApplicationContext getApplicationContext(){ + return applicationContext; + } +} diff --git a/src/main/java/com/mixi/common/utils/export/ProductCellWriteHandler.java b/src/main/java/com/mixi/common/utils/export/ProductCellWriteHandler.java new file mode 100644 index 0000000..f73d10a --- /dev/null +++ b/src/main/java/com/mixi/common/utils/export/ProductCellWriteHandler.java @@ -0,0 +1,89 @@ +package com.mixi.common.utils.export; + +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.util.StyleUtil; +import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import org.apache.poi.ss.usermodel.*; + +import java.util.List; + +/** + * @author yanglei + * @date 2023/5/27 21:04 + */ +public class ProductCellWriteHandler implements CellWriteHandler { + @Override + public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + //当前行的第i列 + int i = cell.getColumnIndex(); + int r = cell.getRowIndex(); + // 根据单元格获取workbook + Sheet sheet = cell.getSheet(); + sheet.setColumnWidth(i,20*256); + Workbook workbook = sheet.getWorkbook(); + if (0 == r) { + // 单元格策略 + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + // 设置背景颜色白色 + //contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex()); + // 设置垂直居中为居中对齐 + contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + // 设置左右对齐为靠左对齐 + contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); + + // 设置单元格上下左右边框为细边框 + contentWriteCellStyle.setBorderBottom(BorderStyle.THIN); + contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); + contentWriteCellStyle.setBorderRight(BorderStyle.THIN); + contentWriteCellStyle.setBorderTop(BorderStyle.THIN); + + contentWriteCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); + contentWriteCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); + contentWriteCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); + contentWriteCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); + + + CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, contentWriteCellStyle); + cellStyle.setWrapText(true); + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//设置前景填充样式 + cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());//前景填充色 + //设置当前行第i列的样式 + cell.getRow().getCell(i).setCellStyle(cellStyle); + } else { + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + // 设置垂直居中为居中对齐 + contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); + // 设置单元格上下左右边框为细边框 + contentWriteCellStyle.setBorderBottom(BorderStyle.THIN); + contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); + contentWriteCellStyle.setBorderRight(BorderStyle.THIN); + contentWriteCellStyle.setBorderTop(BorderStyle.THIN); + + contentWriteCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); + contentWriteCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); + contentWriteCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); + contentWriteCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); + CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, contentWriteCellStyle); + cellStyle.setWrapText(true); + cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//设置前景填充样式 + cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());//前景填充色 + //设置当前行第i列的样式 + cell.getRow().getCell(i).setCellStyle(cellStyle); + } + } +} diff --git a/src/main/java/com/mixi/controller/AccountController.java b/src/main/java/com/mixi/controller/AccountController.java new file mode 100644 index 0000000..db3d63d --- /dev/null +++ b/src/main/java/com/mixi/controller/AccountController.java @@ -0,0 +1,78 @@ +package com.mixi.controller; + +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.model.dto.*; +import com.mixi.model.vo.AccountLoginVO; +import com.mixi.model.vo.AccountVO; +import com.mixi.service.AccountService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +@Api(tags = "账户") +@Slf4j +@RestController +@RequestMapping("/api/account") +public class AccountController { + + @Resource + private AccountService accountService; + + @ApiOperation(value = "用户分页列表") + @PostMapping("/queryUserPage") + public Response> queryUserPage(@Valid @RequestBody QueryAccountPageDTO query) { + return Response.success(accountService.queryUserPage(query)); + } + + @ApiOperation(value = "添加或编辑账号") + @PostMapping("/saveOrEdit") + public Response saveOrEdit(@Valid @RequestBody AccountEditDTO accountEditDTO) { + return Response.success(accountService.saveOrEdit(accountEditDTO)); + } + + @ApiOperation(value = "删除账户") + @PostMapping("/delete") + public Response delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) { + return Response.success(accountService.delete(storeDeleteDTO)); + } + + @ApiOperation(value = "禁用/停用账户") + @PostMapping("/enable") + public Response enableAccount(@Valid @RequestBody AccountEnableDTO accountEnableDTO) { + return Response.success(accountService.enableAccount(accountEnableDTO)); + } + + @ApiOperation(value = "登入") + @PostMapping("/login") + public Response login(@Valid @RequestBody AccountLoginDTO accountDTO) { + return Response.success(accountService.login(accountDTO)); + } + + @ApiOperation(value = "忘记密码") + @PostMapping("/resetPwd") + public Response resetPwd(@Valid @RequestBody AccountRegisterDTO accountRegisterDTO) { + accountService.forgetPwd(accountRegisterDTO); + return Response.success(); + } + @ApiOperation(value = "登出") + @PostMapping("/logout") + public Response logout(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) { + return Response.success( accountService.logout(accountLogoutDTO)); + } + + @ApiOperation(value = "是否登入") + @PostMapping("/isLogin") + public Response isLogin(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) { + return Response.success( accountService.isLogin(accountLogoutDTO)); + } + + +} diff --git a/src/main/java/com/mixi/controller/AppAccountController.java b/src/main/java/com/mixi/controller/AppAccountController.java new file mode 100644 index 0000000..0a5e707 --- /dev/null +++ b/src/main/java/com/mixi/controller/AppAccountController.java @@ -0,0 +1,68 @@ +package com.mixi.controller; + +import com.mixi.common.response.Response; +import com.mixi.model.dto.AccountLoginDTO; +import com.mixi.model.dto.AccountLogoutDTO; +import com.mixi.model.dto.AccountRegisterDTO; +import com.mixi.model.dto.AppAccountLoginDTO; +import com.mixi.model.vo.AccountLoginVO; +import com.mixi.model.vo.AppAccountLoginVO; +import com.mixi.model.vo.StoreVO; +import com.mixi.service.AccountService; +import com.mixi.service.StoreService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +@Api(tags = "app端-账户") +@Slf4j +@RestController +@RequestMapping("/api/app/account") +public class AppAccountController { + @Resource + private AccountService accountService; + @Resource + private StoreService storeService; + + @ApiOperation(value = "app端登入") + @PostMapping("/login") + public Response login(@Valid @RequestBody AppAccountLoginDTO accountDTO) { + return Response.success(accountService.appLogin(accountDTO)); + } + + @ApiOperation(value = "忘记密码") + @PostMapping("/resetPwd") + public Response resetPwd(@Valid @RequestBody AccountRegisterDTO accountRegisterDTO) { + accountService.appForgetPwd(accountRegisterDTO); + return Response.success(); + } + + @ApiOperation(value = "登出") + @PostMapping("/logout") + public Response logout(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) { + return Response.success(accountService.appLogout(accountLogoutDTO)); + } + + @ApiOperation(value = "是否登入") + @PostMapping("/isLogin") + public Response isLogin(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) { + return Response.success(accountService.appIsLogin(accountLogoutDTO)); + } + + @ApiOperation(value = "下拉-查询当前用户店铺") + @PostMapping("/queryUserStore") + public Response> queryUserStore() { + return Response.success(storeService.queryUserStore(null,null)); + } + + + +} diff --git a/src/main/java/com/mixi/controller/AppProductController.java b/src/main/java/com/mixi/controller/AppProductController.java new file mode 100644 index 0000000..9c1c01d --- /dev/null +++ b/src/main/java/com/mixi/controller/AppProductController.java @@ -0,0 +1,98 @@ +package com.mixi.controller; + +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.common.utils.MD5Utils; +import com.mixi.model.dto.*; +import com.mixi.model.vo.*; +import com.mixi.service.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Stream; + +@Api(tags = "App端-商品") +@Slf4j +@RestController +@RequestMapping("/api/app/product") +public class AppProductController { + @Resource + private TAttributeTypeService tAttributeTypeService; + + @Resource + private TProductService tProductService; + @Resource + private TAppProductService tAppProductService; + + @ApiOperation(value = "新品推荐列表") + @PostMapping("/queryNewProductPage") + public Response> queryNewProductPage(@Valid @RequestBody QueryNewProductPageDTO query) { + return Response.success(tAppProductService.queryAppNewProductPage(query)); + } + + @ApiOperation(value = "个性化推荐列表") + @PostMapping("/queryRecommendPage") + public Response> queryRecommendPage(@Valid @RequestBody QueryRecommendPageDTO query) { + return Response.success(tAppProductService.queryRecommendPage(query)); + } + + @ApiOperation(value = "商品销量排行,取前10个") + @PostMapping("/queryProductSaleRank") + public Response> queryProductSaleRank(@Valid @RequestBody QueryProductRankDTO query) { + return Response.success(tAppProductService.queryProductSaleRank(query)); + } + + @ApiOperation(value = "相似度搭配,展示相似度前5") + @PostMapping("/productSimilarityMatch") + public Response> productSimilarityMatch(@Valid @RequestBody ProductSimilaDTO query) { + return Response.success(tAppProductService.productSimilarityMatch(query)); + } + + @ApiOperation(value = "提取主色(默认返回5组主色,前端默认取第一组,识别时候需传5组主色过去python)") + @PostMapping("/colorExtract") + public Response> colorExtract(@Valid @RequestBody ProductColorExtratDTO query) { + return Response.success(tAppProductService.colorExtract(query)); + } + + @ApiOperation(value = "颜色搭配,展示前5") + @PostMapping("/productColorMatch") + public Response> productColorMatch(@Valid @RequestBody ProductColorDTO query) { + return Response.success(tAppProductService.productColorMatch(query)); + } + + @ApiOperation(value = "商品详情") + @GetMapping("/detail") + public Response detail(@ApiParam(value = "商品id") @RequestParam(value = "id") String id) { + return Response.success(tProductService.detail(id)); + } + + @ApiOperation(value = "检索商品分页列表") + @PostMapping("/searchProductPage") + public Response> searchProductPage(@Valid @RequestBody SearchProductPageDTO query) { + return Response.success(tAppProductService.searchProductPage(query)); + } + @ApiOperation(value = "下拉-查询所有属性值") + @GetMapping("/queryAllAttribute") + public Response> queryAllAttribute() { + return Response.success(tAttributeTypeService.queryAll()); + } + + @ApiOperation(value = "app端上传单个文件-要识别的图片(不入库)") + @PostMapping("/uploadFileSingle") + public Response uploadFileSingle(@RequestParam("file") MultipartFile file) { + Assert.isTrue(!StringUtils.isEmpty(file.getOriginalFilename()), "Please select a file!"); + return Response.success(tAppProductService.singleUploadProduct(file, MD5Utils.encryptFile(file))); + } + + +} diff --git a/src/main/java/com/mixi/controller/AttributeTypeController.java b/src/main/java/com/mixi/controller/AttributeTypeController.java new file mode 100644 index 0000000..6dc564a --- /dev/null +++ b/src/main/java/com/mixi/controller/AttributeTypeController.java @@ -0,0 +1,33 @@ +package com.mixi.controller; + +import com.mixi.common.response.Response; +import com.mixi.model.vo.AttributeVO; +import com.mixi.service.TAttributeTypeService; +import com.mixi.service.TAttributeValueService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import jdk.nashorn.internal.objects.annotations.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "python属性值") +@Slf4j +@RestController +@RequestMapping("/api/attribute") +public class AttributeTypeController { + + @Resource + private TAttributeTypeService tAttributeTypeService; + @Resource + private TAttributeValueService tAttributeValueService; + + @ApiOperation(value = "下拉-查询所有属性值") + @GetMapping("/queryAll") + public Response> queryAll() { + return Response.success(tAttributeTypeService.queryAll()); + } + +} diff --git a/src/main/java/com/mixi/controller/CustomController.java b/src/main/java/com/mixi/controller/CustomController.java new file mode 100644 index 0000000..5dbab04 --- /dev/null +++ b/src/main/java/com/mixi/controller/CustomController.java @@ -0,0 +1,61 @@ +package com.mixi.controller; + +import com.mixi.common.response.Response; +import com.mixi.mapper.entity.TCustomBuriedPointRecord; +import com.mixi.model.dto.CustomBuriedPointDTO; +import com.mixi.model.dto.CustomLogoutDTO; +import com.mixi.model.dto.CustomRegisterDTO; +import com.mixi.model.dto.LabelAddOrEditDTO; +import com.mixi.model.vo.CustomRegisterVO; +import com.mixi.service.TCustomBuriedPointRecordService; +import com.mixi.service.TCustomRegisterService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + + +/** + *

+ * 客户登入 前端控制器 + *

+ * + * @author yanglei + * @since 2023-04-01 + */ +@Api(tags = "App端-客户") +@Slf4j +@RestController +@RequestMapping("/api/app/custom") +public class CustomController { + @Resource + private TCustomRegisterService tCustomRegisterService; + @Resource + private TCustomBuriedPointRecordService tCustomBuriedPointRecordService; + + @ApiOperation(value = "客户登入") + @PostMapping("/register") + public Response register(@Valid @RequestBody CustomRegisterDTO customRegisterDTO) { + return Response.success(tCustomRegisterService.register(customRegisterDTO)); + } + + @ApiOperation(value = "客户登出") + @PostMapping("/logout") + public Response logout(@Valid @RequestBody CustomLogoutDTO customLogoutDTO) { + tCustomRegisterService.logout(customLogoutDTO); + return Response.success(); + } + + @ApiOperation(value = "客户数据埋点") + @PostMapping("/buriedPoint") + public Response buriedPoint(@Valid @RequestBody CustomBuriedPointDTO customBuriedPointDTO) { + tCustomBuriedPointRecordService.buriedPoint(customBuriedPointDTO); + return Response.success(); + } +} diff --git a/src/main/java/com/mixi/controller/LabelController.java b/src/main/java/com/mixi/controller/LabelController.java new file mode 100644 index 0000000..4b33487 --- /dev/null +++ b/src/main/java/com/mixi/controller/LabelController.java @@ -0,0 +1,55 @@ +package com.mixi.controller; + +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.model.dto.*; +import com.mixi.model.vo.AllRoleVO; +import com.mixi.model.vo.LabelVO; +import com.mixi.model.vo.StoreVO; +import com.mixi.service.LabelService; +import com.mixi.service.StoreService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +@Api(tags = "标签管理") +@Slf4j +@RestController +@RequestMapping("/api/label") +public class LabelController { + + @Resource + private LabelService labelService; + + @ApiOperation(value = "标签分页列表") + @PostMapping("/queryStorePage") + public Response> queryStorePage(@Valid @RequestBody QueryLabelPageDTO query) { + return Response.success(labelService.queryLabelPage(query)); + } + + @ApiOperation(value = "新增或编辑标签") + @PostMapping("/saveOrEdit") + public Response saveOrEdit(@Valid @RequestBody LabelAddOrEditDTO labelAddOrEditDTO) { + return Response.success(labelService.saveOrEdit(labelAddOrEditDTO)); + } + + @ApiOperation(value = "删除标签") + @PostMapping("/delete") + public Response delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) { + return Response.success(labelService.delete(storeDeleteDTO)); + } + @ApiOperation(value = "下拉-查询所有商品标签") + @PostMapping("/queryProductLabel") + public Response> queryAll() { + return Response.success(labelService.queryProductLabel()); + } + +} diff --git a/src/main/java/com/mixi/controller/MiTuExportController.java b/src/main/java/com/mixi/controller/MiTuExportController.java new file mode 100644 index 0000000..b3b6002 --- /dev/null +++ b/src/main/java/com/mixi/controller/MiTuExportController.java @@ -0,0 +1,49 @@ +package com.mixi.controller; + +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.mapper.entity.MiTuExport; +import com.mixi.model.dto.QueryMiTuExportPageDTO; +import com.mixi.model.dto.QueryStorePageDTO; +import com.mixi.model.dto.StoreAddOrEditDTO; +import com.mixi.model.dto.StoreDeleteDTO; +import com.mixi.model.vo.StoreVO; +import com.mixi.service.MiTuExportService; +import com.mixi.service.StoreService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.FileNotFoundException; +import java.util.List; + +@Api(tags = "mi-tu报表") +@Slf4j +@RestController +@RequestMapping("/api/miTuExport") +public class MiTuExportController { + + @Resource + private MiTuExportService miTuExportService; + + @ApiOperation(value = "MiTu报表查询") + @PostMapping("/miTuExportPage") + public Response> queryMiTuExportPage(@Valid @RequestBody QueryMiTuExportPageDTO query) { + return Response.success(miTuExportService.queryMiTuExportPage(query)); + } + + @ApiOperation(value = "下载MiTu报表") + @GetMapping("/export/{id}") + public void exportMiTuReport(@PathVariable Long id, HttpServletResponse response) throws FileNotFoundException { + miTuExportService.exportMiTuReport(id, response); + } + + +} diff --git a/src/main/java/com/mixi/controller/ProductController.java b/src/main/java/com/mixi/controller/ProductController.java new file mode 100644 index 0000000..52686da --- /dev/null +++ b/src/main/java/com/mixi/controller/ProductController.java @@ -0,0 +1,130 @@ +package com.mixi.controller; + +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.common.utils.MD5Utils; +import com.mixi.model.dto.*; +import com.mixi.model.vo.*; +import com.mixi.service.TProductService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +@Api(tags = "商品管理") +@Slf4j +@RestController +@RequestMapping("/api/product") +public class ProductController { + + @Resource + private TProductService tProductService; + + @ApiOperation(value = "首页工作台统计") + @GetMapping("/countWorkBench") + public Response countWorkBench(String storeId) { + return Response.success(tProductService.countWorkBench(storeId)); + } + + @ApiOperation(value = "商品分页列表") + @PostMapping("/queryProductPage") + public Response> queryProductPage(@Valid @RequestBody QueryProductPageDTO query) { + return Response.success(tProductService.queryProductPage(query)); + } + @ApiOperation(value = "商品导出") + @PostMapping("/exportProduct") + public Response exportProduct(@Valid @RequestBody QueryProductPageDTO query) throws IOException { + return Response.successData(tProductService.exportProduct(query)); + } + + @ApiOperation(value = "商品详情") + @GetMapping("/detail") + public Response detail(@ApiParam(value = "商品id") @RequestParam(value = "id") String id) { + return Response.success(tProductService.detail(id)); + } + + @ApiOperation(value = "编辑商品") + @PostMapping("/edit") + public Response edit(@Valid @RequestBody EditProductDTO editProductDTO) { + return Response.success(tProductService.edit(editProductDTO)); + } + + @ApiOperation(value = "删除商品") + @PostMapping("/delete") + public Response delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) { + return Response.success(tProductService.delete(storeDeleteDTO)); + } + + @ApiOperation(value = "批量上传商品,前端适配不了 暂时不用") + @PostMapping("/batchUploadProduct") + public Response batchUploadProduct(@RequestParam("files") MultipartFile[] files, + @ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + @RequestParam(value = "timeZone") String timeZone) { + Assert.notNull(files,"Please select a file !"); + Assert.isTrue(files.length <=10,"A maximum of 10 images can be uploaded !"); + Stream.of(files).forEach(file ->{ + Assert.isTrue(!StringUtils.isEmpty(file.getOriginalFilename()),"Please select a file!"); + }); + return Response.success(tProductService.batchUploadProduct(files,timeZone)); + } + @ApiOperation(value = "上传单个文件,保存用") + @PostMapping("/uploadFileSingle") + public Response uploadFileSingle(@RequestParam("file") MultipartFile file, + @ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + @RequestParam(value = "timeZone") String timeZone) { + Assert.isTrue(!StringUtils.isEmpty(file.getOriginalFilename()), "Please select a file!"); + return Response.success(tProductService.singleUploadProduct(file, MD5Utils.encryptFile(file),timeZone)); + } + + @ApiOperation(value = "批量上传商品后传对应的关联信息") + @PostMapping("/batchUploadProductRelation") + public Response batchUploadProductRelation(@Valid @RequestBody BatchUploadProductDTO product) { + return Response.success(tProductService.batchUploadProductRelation(product)); + } + + @ApiOperation(value = "商品搭配分页列表") + @PostMapping("/queryProductAssortmentPage") + public Response> queryProductAssortmentPage(@Valid @RequestBody QueryProductAssortmentPageDTO query) { + return Response.success(tProductService.queryProductAssortmentPage(query)); + } + + @ApiOperation(value = "上传文件,编辑用") + @PostMapping("/uploadFile") + public Response uploadFile(@RequestParam("file") MultipartFile file, + @ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + @RequestParam(value = "timeZone") String timeZone, + @ApiParam("商品id") @RequestParam(value = "id") String id) { + Assert.isTrue(!StringUtils.isEmpty(file.getOriginalFilename()), "Please select a file!"); + return Response.success(tProductService.upload(file, MD5Utils.encryptFile(file),timeZone,id)); + } + + @ApiOperation(value = "统计商品批量上传进度") + @PostMapping("/countProductUpdateProcess") + public Response countProductUpdateProcess() { + return Response.success(tProductService.countProductUpdateProcess()); + } + + @ApiOperation(value = "上架/下架商品") + @PostMapping("/doOnSale") + public Response enableAccount(@Valid @RequestBody ProductOnSaleDTO productOnSaleDTO) { + return Response.success(tProductService.enableAccount(productOnSaleDTO)); + } + + @ApiOperation(value = "获取category") + @GetMapping("/getCategory") + public Response> getCategory(@RequestParam("category") String category) { + return Response.success(tProductService.getCategory(category)); + } + +} diff --git a/src/main/java/com/mixi/controller/RoleController.java b/src/main/java/com/mixi/controller/RoleController.java new file mode 100644 index 0000000..1c2aacf --- /dev/null +++ b/src/main/java/com/mixi/controller/RoleController.java @@ -0,0 +1,66 @@ +package com.mixi.controller; + +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.model.dto.QueryStorePageDTO; +import com.mixi.model.dto.RoleAddOrEditDTO; +import com.mixi.model.dto.StoreDeleteDTO; +import com.mixi.model.vo.AllRoleVO; +import com.mixi.model.vo.RolePermission1VO; +import com.mixi.model.vo.RoleVO; +import com.mixi.model.vo.StoreVO; +import com.mixi.service.RoleService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +@Api(tags = "角色管理") +@Slf4j +@RestController +@RequestMapping("/api/role") +public class RoleController { + + @Resource + private RoleService roleService; + + @ApiOperation(value = "角色分页列表") + @PostMapping("/queryRolePage") + public Response> queryStorePage(@Valid @RequestBody QueryStorePageDTO query) { + return Response.success(roleService.queryRolePage(query)); + } + + @ApiOperation(value = "查询权限列表") + @GetMapping("/queryPermissionList") + public Response> queryPermissionList() { + return Response.success(roleService.queryPermissionListTemplate()); + } + + @ApiOperation(value = "新增或编辑角色") + @PostMapping("/saveOrEdit") + public Response saveOrEdit(@Valid @RequestBody RoleAddOrEditDTO roleAddOrEditDTO) { + return Response.success(roleService.saveOrEdit(roleAddOrEditDTO)); + } + + @ApiOperation(value = "删除标签") + @PostMapping("/delete") + public Response delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) { + return Response.success(roleService.delete(storeDeleteDTO)); + } + @ApiOperation(value = "下拉-查询所有角色") + @PostMapping("/queryAll") + public Response> queryAll() { + return Response.success(roleService.queryAll()); + } + + @ApiOperation(value = "查询用户角色权限") + @GetMapping("/queryUsrPermission") + public Response queryUsrPermission() { + return Response.success(roleService.queryUsrPermission()); + } + +} diff --git a/src/main/java/com/mixi/controller/StoreController.java b/src/main/java/com/mixi/controller/StoreController.java new file mode 100644 index 0000000..80f7ede --- /dev/null +++ b/src/main/java/com/mixi/controller/StoreController.java @@ -0,0 +1,62 @@ +package com.mixi.controller; + +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.model.dto.*; +import com.mixi.model.vo.AccountLoginVO; +import com.mixi.model.vo.AccountVO; +import com.mixi.model.vo.LabelVO; +import com.mixi.model.vo.StoreVO; +import com.mixi.service.AccountService; +import com.mixi.service.StoreService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +@Api(tags = "门店管理") +@Slf4j +@RestController +@RequestMapping("/api/store") +public class StoreController { + + @Resource + private StoreService storeService; + + @ApiOperation(value = "门店分页列表") + @PostMapping("/queryStorePage") + public Response> queryStorePage(@Valid @RequestBody QueryStorePageDTO query) { + return Response.success(storeService.queryStorePage(query)); + } + + @ApiOperation(value = "新增或编辑门店") + @PostMapping("/saveOrEdit") + public Response saveOrEdit(@Valid @RequestBody StoreAddOrEditDTO storeAddOrEditDTO) { + return Response.success(storeService.saveOrEdit(storeAddOrEditDTO)); + } + + @ApiOperation(value = "删除门店") + @PostMapping("/delete") + public Response delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) { + return Response.success(storeService.delete(storeDeleteDTO)); + } + @ApiOperation(value = "下拉-查询所有店铺") + @PostMapping("/queryAll") + public Response> queryAll() { + return Response.success(storeService.queryAll()); + } + + @ApiOperation(value = "下拉-查询所有商品店铺") + @PostMapping("/queryProductStore") + public Response> queryProductStore() { + return Response.success(storeService.queryUserStore(null,null)); + } + +} diff --git a/src/main/java/com/mixi/mapper/AccountMapper.java b/src/main/java/com/mixi/mapper/AccountMapper.java new file mode 100644 index 0000000..646b590 --- /dev/null +++ b/src/main/java/com/mixi/mapper/AccountMapper.java @@ -0,0 +1,14 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TAccount; + +/** + * Mapper 接口 + * + * @author easy-generator + * @since 2022-06-13 + */ +public interface AccountMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/ColorLoopUpTableMapper.java b/src/main/java/com/mixi/mapper/ColorLoopUpTableMapper.java new file mode 100644 index 0000000..93b0200 --- /dev/null +++ b/src/main/java/com/mixi/mapper/ColorLoopUpTableMapper.java @@ -0,0 +1,15 @@ +package com.mixi.mapper; + + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.ColorLookupTable; + +/** + * Mapper 接口 + * + * @author easy-generator + * @since 2022-09-30 + */ +public interface ColorLoopUpTableMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/MiTuExportMapper.java b/src/main/java/com/mixi/mapper/MiTuExportMapper.java new file mode 100644 index 0000000..acb235e --- /dev/null +++ b/src/main/java/com/mixi/mapper/MiTuExportMapper.java @@ -0,0 +1,16 @@ +package com.mixi.mapper; + + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.ColorLookupTable; +import com.mixi.mapper.entity.MiTuExport; + +/** + * Mapper 接口 + * + * @author easy-generator + * @since 2022-09-30 + */ +public interface MiTuExportMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/MiTuProductMapper.java b/src/main/java/com/mixi/mapper/MiTuProductMapper.java new file mode 100644 index 0000000..27d5794 --- /dev/null +++ b/src/main/java/com/mixi/mapper/MiTuProductMapper.java @@ -0,0 +1,15 @@ +package com.mixi.mapper; + + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.MiTuProduct; + +/** + * Mapper 接口 + * + * @author easy-generator + * @since 2022-09-30 + */ +public interface MiTuProductMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/PanToneMapper.java b/src/main/java/com/mixi/mapper/PanToneMapper.java new file mode 100644 index 0000000..7f9055d --- /dev/null +++ b/src/main/java/com/mixi/mapper/PanToneMapper.java @@ -0,0 +1,19 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.PanTone; +import com.mixi.model.dto.GetRgbByHsvBatchDTO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * Mapper 接口 + * + * @author easy-generator + * @since 2022-06-13 + */ +public interface PanToneMapper extends CommonMapper { + + List getRgbByHsvBatch(@Param("rgbByHsvBatch") List rgbByHsvBatch); +} diff --git a/src/main/java/com/mixi/mapper/TAccountMapper.java b/src/main/java/com/mixi/mapper/TAccountMapper.java new file mode 100644 index 0000000..ddceca3 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TAccountMapper.java @@ -0,0 +1,17 @@ +package com.mixi.mapper; + + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TAccount; + +/** + *

+ * 账户表,用户表 Mapper 接口 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +public interface TAccountMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TAccountStoreMapper.java b/src/main/java/com/mixi/mapper/TAccountStoreMapper.java new file mode 100644 index 0000000..440c846 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TAccountStoreMapper.java @@ -0,0 +1,16 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TAccountStore; + +/** + *

+ * 用户店铺关联表 Mapper 接口 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +public interface TAccountStoreMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TAttributeTypeMapper.java b/src/main/java/com/mixi/mapper/TAttributeTypeMapper.java new file mode 100644 index 0000000..37e1b3a --- /dev/null +++ b/src/main/java/com/mixi/mapper/TAttributeTypeMapper.java @@ -0,0 +1,18 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TAttributeType; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 属性类型表 Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Mapper +public interface TAttributeTypeMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TAttributeValueMapper.java b/src/main/java/com/mixi/mapper/TAttributeValueMapper.java new file mode 100644 index 0000000..e66fe82 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TAttributeValueMapper.java @@ -0,0 +1,19 @@ +package com.mixi.mapper; + +import com.mixi.mapper.entity.TAttributeValue; +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TAttributeValue; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 属性值表(对应python识别的标签信息) Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Mapper +public interface TAttributeValueMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TCustomBuriedPointRecordMapper.java b/src/main/java/com/mixi/mapper/TCustomBuriedPointRecordMapper.java new file mode 100644 index 0000000..7c77738 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TCustomBuriedPointRecordMapper.java @@ -0,0 +1,18 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TCustomBuriedPointRecord; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 客户埋点记录表 Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-04-01 + */ +@Mapper +public interface TCustomBuriedPointRecordMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TCustomRegisterMapper.java b/src/main/java/com/mixi/mapper/TCustomRegisterMapper.java new file mode 100644 index 0000000..f992667 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TCustomRegisterMapper.java @@ -0,0 +1,19 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TCustomRegister; +import org.apache.ibatis.annotations.Mapper; + + +/** + *

+ * 客户登入记录表 Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-04-01 + */ +@Mapper +public interface TCustomRegisterMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TLablelMapper.java b/src/main/java/com/mixi/mapper/TLablelMapper.java new file mode 100644 index 0000000..b219bae --- /dev/null +++ b/src/main/java/com/mixi/mapper/TLablelMapper.java @@ -0,0 +1,16 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TLabel; + +/** + *

+ * 标签表 Mapper 接口 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +public interface TLablelMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TProductAssortmentMapper.java b/src/main/java/com/mixi/mapper/TProductAssortmentMapper.java new file mode 100644 index 0000000..b5b165c --- /dev/null +++ b/src/main/java/com/mixi/mapper/TProductAssortmentMapper.java @@ -0,0 +1,18 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TProductAssortment; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 商品搭配表 Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ + +public interface TProductAssortmentMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TProductAttributeMapper.java b/src/main/java/com/mixi/mapper/TProductAttributeMapper.java new file mode 100644 index 0000000..4553101 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TProductAttributeMapper.java @@ -0,0 +1,18 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TProductAttribute; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 商品属性关联表 Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-03-19 + */ +@Mapper +public interface TProductAttributeMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TProductBatchMapper.java b/src/main/java/com/mixi/mapper/TProductBatchMapper.java new file mode 100644 index 0000000..29886b6 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TProductBatchMapper.java @@ -0,0 +1,19 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TProductBatch; +import org.apache.ibatis.annotations.Mapper; + + +/** + *

+ * 商品批次表 Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Mapper +public interface TProductBatchMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TProductLabelMapper.java b/src/main/java/com/mixi/mapper/TProductLabelMapper.java new file mode 100644 index 0000000..8511ae4 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TProductLabelMapper.java @@ -0,0 +1,16 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TProductLabel; + +/** + *

+ * 标签商品关联表 Mapper 接口 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +public interface TProductLabelMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TProductMapper.java b/src/main/java/com/mixi/mapper/TProductMapper.java new file mode 100644 index 0000000..51a4874 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TProductMapper.java @@ -0,0 +1,18 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TProduct; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 商品表 Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Mapper +public interface TProductMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TProductStockMapper.java b/src/main/java/com/mixi/mapper/TProductStockMapper.java new file mode 100644 index 0000000..d305400 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TProductStockMapper.java @@ -0,0 +1,18 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TProductStock; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 商品库存关联表 Mapper 接口 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Mapper +public interface TProductStockMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TRoleMapper.java b/src/main/java/com/mixi/mapper/TRoleMapper.java new file mode 100644 index 0000000..edaa2c7 --- /dev/null +++ b/src/main/java/com/mixi/mapper/TRoleMapper.java @@ -0,0 +1,16 @@ +package com.mixi.mapper; + +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TRole; + +/** + *

+ * 角色表 Mapper 接口 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +public interface TRoleMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/TStoreMapper.java b/src/main/java/com/mixi/mapper/TStoreMapper.java new file mode 100644 index 0000000..4b078ac --- /dev/null +++ b/src/main/java/com/mixi/mapper/TStoreMapper.java @@ -0,0 +1,15 @@ +package com.mixi.mapper; +import com.mixi.common.config.mybatis.plus.CommonMapper; +import com.mixi.mapper.entity.TStore; + +/** + *

+ * 店铺表 Mapper 接口 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +public interface TStoreMapper extends CommonMapper { + +} diff --git a/src/main/java/com/mixi/mapper/entity/ColorLookupTable.java b/src/main/java/com/mixi/mapper/entity/ColorLookupTable.java new file mode 100644 index 0000000..2408a7f --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/ColorLookupTable.java @@ -0,0 +1,32 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * Attendance + * + * @author easy-generator + * @since 2022-09-30 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("color_lookup_table") +public class ColorLookupTable implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * colorValue + */ + private Integer colorValue; + + /** + * color_index + */ + private Integer colorIndex; +} diff --git a/src/main/java/com/mixi/mapper/entity/MiTuExport.java b/src/main/java/com/mixi/mapper/entity/MiTuExport.java new file mode 100644 index 0000000..4e2db03 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/MiTuExport.java @@ -0,0 +1,37 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +@Data +public class MiTuExport implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + + private String exportName; + + private String dataTime; + + private String url; + + private LocalDateTime createTime; + + private String span; + + /** + * 0未完成1已完成 + */ + private Integer status; +} diff --git a/src/main/java/com/mixi/mapper/entity/MiTuProduct.java b/src/main/java/com/mixi/mapper/entity/MiTuProduct.java new file mode 100644 index 0000000..b5b2d6e --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/MiTuProduct.java @@ -0,0 +1,45 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("mi_tu_product") +public class MiTuProduct implements Serializable { + + private static final long serialVersionUID = 1L; + + // 关联t_product id + @TableId(value = "id", type = IdType.AUTO) + private Long id; + private Long productId; + private String pluCode; + private String itemCode; + private String itemName; + private String itemBarcode; + private String unit; + private String itemType; + private int qtyOnHand; + private int qtyOnOrd; + private double priceSales; + private String brand; + private String gender; + private String year; + private String season; + private String sampleNon; + private String itemGroup; + private String subGroup; + private String country; + private String supplier; + private String size; + private String color; + private String image; +} diff --git a/src/main/java/com/mixi/mapper/entity/PanTone.java b/src/main/java/com/mixi/mapper/entity/PanTone.java new file mode 100644 index 0000000..6a5e640 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/PanTone.java @@ -0,0 +1,68 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * Attendance + * + * @author easy-generator + * @since 2022-06-13 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("pantone") +public class PanTone implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * pantone_index + */ + private Integer pantoneIndex; + + /** + * name + */ + private String name; + + /** + * TCX + */ + private String tcx; + + /** + * R + */ + private Integer r; + + /** + * G + */ + private Integer g; + + /** + * B + */ + private Integer b; + + /** + * H + */ + private Integer h; + + /** + * S + */ + private Integer s; + + /** + *V + */ + private Integer v; +} diff --git a/src/main/java/com/mixi/mapper/entity/TAccount.java b/src/main/java/com/mixi/mapper/entity/TAccount.java new file mode 100644 index 0000000..dadf4df --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TAccount.java @@ -0,0 +1,131 @@ +package com.mixi.mapper.entity; + + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + *

+ * 账户表,用户表 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("t_account") +public class TAccount implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + /** + * 用户名 + */ + @TableField("user_name") + private String userName; + /** + * 用户账户 + */ + @TableField("user_account") + private String userAccount; + /** + * 用户手机号 + */ + @TableField("user_phone") + private String userPhone; + /** + * 密码(用户code) MD5加密 + */ + @TableField("user_password") + private String userPassword; + /** + * 关联的角色id ,只能一个角色 + */ + @TableField("role_id") + private Long roleId; + /** + * 是否app用户 1是 0不是 + */ + @TableField("app_user") + private Integer appUser; + /** + * 备注 + */ + private String remarks; + /** + * 启用状态 1启用中 0已停用 + */ + private Integer state; + /** + * 创建时间 + */ + @TableField("create_date") + private Date createDate; + /** + * 更新时间 + */ + @TableField("update_date") + private Date updateDate; + + + /** + * ID + */ + public static final String ID = "id"; + /** + * 用户名 + */ + public static final String USER_NAME = "user_name"; + /** + * 用户账户 + */ + public static final String USER_ACCOUNT = "user_account"; + /** + * 用户手机号 + */ + public static final String USER_PHONE = "user_phone"; + /** + * 密码(用户code) MD5加密 + */ + public static final String USER_PASSWORD = "user_password"; + /** + * 关联的角色id ,只能一个角色 + */ + public static final String ROLE_ID = "role_id"; + /** + * 是否app用户 1是 0不是 + */ + public static final String APP_USER = "app_user"; + /** + * 备注 + */ + public static final String REMARKS = "remarks"; + /** + * 启用状态 1启用中 0已停用 + */ + public static final String STATE = "state"; + /** + * 创建时间 + */ + public static final String CREATE_DATE = "create_date"; + /** + * 更新时间 + */ + public static final String UPDATE_DATE = "update_date"; +} diff --git a/src/main/java/com/mixi/mapper/entity/TAccountStore.java b/src/main/java/com/mixi/mapper/entity/TAccountStore.java new file mode 100644 index 0000000..1772b33 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TAccountStore.java @@ -0,0 +1,66 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.util.Date; + +/** + *

+ * 用户店铺关联表 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("t_account_store") +public class TAccountStore implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + /** + * 用户id + */ + @TableField("account_id") + private Long accountId; + /** + * 店铺id + */ + @TableField("store_id") + private Long storeId; + /** + * 创建时间 + */ + @TableField("create_date") + private Date createDate; + + + /** + * ID + */ + public static final String ID = "id"; + /** + * 用户id + */ + public static final String ACCOUNT_ID = "account_id"; + /** + * 店铺id + */ + public static final String STORE_ID = "store_id"; + /** + * 创建时间 + */ + public static final String CREATE_DATE = "create_date"; +} diff --git a/src/main/java/com/mixi/mapper/entity/TAttributeType.java b/src/main/java/com/mixi/mapper/entity/TAttributeType.java new file mode 100644 index 0000000..d23378e --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TAttributeType.java @@ -0,0 +1,50 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import springfox.documentation.service.ApiListing; + +/** + *

+ * 属性类型表 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("t_attribute_type") +@ApiModel(value = "TAttributeType对象", description = "属性类型表") +public class TAttributeType implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("Label Item 包括 Top Shoes Dress Jumpsuit Coat Outwear") + private String labelItem; + + @ApiModelProperty("Label Type 每个label_item 对应不同的attribute") + private String labelType; + + @ApiModelProperty("创建时间") + private Date createDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TAttributeValue.java b/src/main/java/com/mixi/mapper/entity/TAttributeValue.java new file mode 100644 index 0000000..754a085 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TAttributeValue.java @@ -0,0 +1,50 @@ +package com.mixi.mapper.entity; + + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** + *

+ * 属性值表(对应python识别的标签信息) + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("t_attribute_value") +@ApiModel(value = "TAttributeValue对象", description = "属性值表(对应python识别的标签信息)") +public class TAttributeValue implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("属性类型id") + private Long attributeTypeId; + + @ApiModelProperty("属性值") + private String attributeValue; + + @ApiModelProperty("创建时间") + private Date createDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TCustomBuriedPointRecord.java b/src/main/java/com/mixi/mapper/entity/TCustomBuriedPointRecord.java new file mode 100644 index 0000000..8d75926 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TCustomBuriedPointRecord.java @@ -0,0 +1,56 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +/** + *

+ * 客户埋点记录表 + *

+ * + * @author yanglei + * @since 2023-04-01 + */ +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@Accessors(chain = true) +@TableName("t_custom_buried_point_record") +@ApiModel(value = "TCustomBuriedPointRecord对象", description = "客户埋点记录表") +public class TCustomBuriedPointRecord implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("埋点类型 BROWSE 浏览 PURCHASE 购买") + private String type; + + @ApiModelProperty("客户id") + private Long customId; + + @ApiModelProperty("客户登入的账号id(用户)") + private Long accountId; + + @ApiModelProperty("客户登入的店铺id") + private Long storeId; + + @ApiModelProperty("对应埋点的商品id") + private Long productId; + + @ApiModelProperty("创建时间") + private Date createDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TCustomRegister.java b/src/main/java/com/mixi/mapper/entity/TCustomRegister.java new file mode 100644 index 0000000..5ed4a74 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TCustomRegister.java @@ -0,0 +1,56 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +/** + *

+ * 客户登入记录表 + *

+ * + * @author yanglei + * @since 2023-04-01 + */ +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Accessors(chain = true) +@TableName("t_custom_register") +@ApiModel(value = "TCustomRegister对象", description = "客户登入记录表") +public class TCustomRegister implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("客户手机号") + private String phone; + + @ApiModelProperty("客户登入的账号id") + private Long accountId; + + @ApiModelProperty("客户登入的店铺id") + private Long storeId; + + @ApiModelProperty("登入状态 1已登入 0已退出") + private Integer state; + + @ApiModelProperty("创建时间") + private Date createDate; + + @ApiModelProperty("更新时间") + private Date updateDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TLabel.java b/src/main/java/com/mixi/mapper/entity/TLabel.java new file mode 100644 index 0000000..e92a431 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TLabel.java @@ -0,0 +1,91 @@ +package com.mixi.mapper.entity; + + +import java.util.Date; +import java.io.Serializable; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import javax.validation.constraints.NotBlank; + +/** + *

+ * 标签表 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +@NoArgsConstructor +@AllArgsConstructor +@Builder +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("t_label") +public class TLabel implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + /** + * 标签名称 + */ + private String name; + /** + * 标签类型 + */ + private String type; + /** + * 备注 + */ + private String remarks; + /** + * 创建人id + */ + @TableField("create_user") + private Long createUser; + /** + * 创建时间 + */ + @TableField("create_date") + private Date createDate; + /** + * 更新时间 + */ + @TableField("update_date") + private Date updateDate; + + + /** + * ID + */ + public static final String ID = "id"; + /** + * 标签名称 + */ + public static final String NAME = "name"; + /** + * 标签类型 + */ + public static final String TYPE = "type"; + /** + * 备注 + */ + public static final String REMARKS = "remarks"; + /** + * 创建时间 + */ + public static final String CREATE_DATE = "create_date"; + /** + * 更新时间 + */ + public static final String UPDATE_DATE = "update_date"; +} diff --git a/src/main/java/com/mixi/mapper/entity/TProduct.java b/src/main/java/com/mixi/mapper/entity/TProduct.java new file mode 100644 index 0000000..80a2f0e --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TProduct.java @@ -0,0 +1,84 @@ +package com.mixi.mapper.entity; + + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Date; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** + *

+ * 商品表 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Data +//@Accessors(chain = true) +@TableName("t_product") +@ApiModel(value = "TProduct对象", description = "商品表") +public class TProduct implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("账户id") + private Long accountId; + + @ApiModelProperty("商品批次id") + private Long batchId; + + @ApiModelProperty("商品主图url") + private String pictureUrl; + + @ApiModelProperty("商品主图名字") + private String pictureName; + + @ApiModelProperty("商品主图md5值") + private String md5; + + @ApiModelProperty("商品总数") + private Integer total; + + @ApiModelProperty("商品状态 1上架 0下架") + private Integer onSaleState; + + @ApiModelProperty("上传状态,记录上传到python识别的整个过程 0上传中 1已上传 2上传失败") + private Integer uploadState; + + @ApiModelProperty("搭配状态,记录识别的商品是否生成搭配 0未生成搭配 1已生成搭配") + private Integer collocationState; + + @ApiModelProperty("商品价格,港币(前端写死)") + private BigDecimal price; + + @ApiModelProperty("颜色,pantone值") + private String color; + + @ApiModelProperty("颜色,rgb值,下划线分割") + private String rgb; + + @ApiModelProperty("创建时间") + private Date createDate; + + @ApiModelProperty("更新时间") + private Date updateDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TProductAssortment.java b/src/main/java/com/mixi/mapper/entity/TProductAssortment.java new file mode 100644 index 0000000..9c92537 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TProductAssortment.java @@ -0,0 +1,54 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + *

+ * 商品搭配表 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Builder +@Data +//@Accessors(chain = true) +@TableName("t_product_assortment") +@ApiModel(value = "TProductAssortment对象", description = "商品搭配表") +public class TProductAssortment implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("被搭配商品id") + private Long productId; + + @ApiModelProperty("搭配的商品id") + private Long assortmentProductId; + + @ApiModelProperty("生成的搭配图地址") + private String generatePictureUrl; + + @ApiModelProperty("套的顺序 1 2 3 4 表示第一套 第二套等") + private Integer coverSort; + + @ApiModelProperty("创建时间") + private Date createDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TProductAttribute.java b/src/main/java/com/mixi/mapper/entity/TProductAttribute.java new file mode 100644 index 0000000..a08e551 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TProductAttribute.java @@ -0,0 +1,52 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.*; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +/** + *

+ * 商品属性关联表 + *

+ * + * @author yanglei + * @since 2023-03-19 + */ +@Getter +@Setter +@Accessors(chain = true) +@TableName("t_product_attribute") +@ApiModel(value = "TProductAttribute对象", description = "商品属性关联表") +public class TProductAttribute implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("商品id") + private Long productId; + + @ApiModelProperty("属性类型Item") + private String attributeItem; + + @ApiModelProperty("属性类型") + private String attributeType; + + @ApiModelProperty("属性值") + private String attributeValue; + + @ApiModelProperty("创建时间") +// @TableField(fill = FieldFill.INSERT) + private Date createDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TProductBatch.java b/src/main/java/com/mixi/mapper/entity/TProductBatch.java new file mode 100644 index 0000000..27ccd2d --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TProductBatch.java @@ -0,0 +1,53 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** + *

+ * 商品批次表 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Getter +@Setter +@Accessors(chain = true) +@Builder +@TableName("t_product_batch") +@ApiModel(value = "TProductBatch对象", description = "商品批次表") +public class TProductBatch implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("一次上传批次总商品数") + private Integer batchProductTotal; + + @ApiModelProperty("创建时间") +// @TableField(fill = FieldFill.INSERT) + private Date createDate; + + @ApiModelProperty("更新时间") +// @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TProductLabel.java b/src/main/java/com/mixi/mapper/entity/TProductLabel.java new file mode 100644 index 0000000..b8ec2cd --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TProductLabel.java @@ -0,0 +1,71 @@ +package com.mixi.mapper.entity; + + +import java.util.Date; +import java.io.Serializable; + + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + *

+ * 商品标签关联表 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("t_product_label") +@Builder +public class TProductLabel implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + /** + * 标签id + */ + @TableField("label_id") + private Long labelId; + /** + * 商品id + */ + @TableField("product_id") + private Long productId; + /** + * 创建时间 + */ + @TableField("create_date") + private Date createDate; + + + /** + * ID + */ + public static final String ID = "id"; + /** + * 标签id + */ + public static final String LABEL_ID = "label_id"; + /** + * 商品id + */ + public static final String PRODUCT_ID = "product_id"; + /** + * 创建时间 + */ + public static final String CREATE_DATE = "create_date"; +} diff --git a/src/main/java/com/mixi/mapper/entity/TProductStock.java b/src/main/java/com/mixi/mapper/entity/TProductStock.java new file mode 100644 index 0000000..da31ebf --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TProductStock.java @@ -0,0 +1,54 @@ +package com.mixi.mapper.entity; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.Date; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +/** + *

+ * 商品库存关联表 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Getter +@Setter +@Accessors(chain = true) +@Builder +@TableName("t_product_stock") +@ApiModel(value = "TProductStock对象", description = "商品库存关联表") +public class TProductStock implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("ID") + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + @ApiModelProperty("商品id") + private Long productId; + + @ApiModelProperty("门店id") + private Long storeId; + + @ApiModelProperty("库存内容json,减少该表数据量,尺寸和尺寸数量存json") + private String stockContent; + + @ApiModelProperty("创建时间") + private Date createDate; + + +} diff --git a/src/main/java/com/mixi/mapper/entity/TRole.java b/src/main/java/com/mixi/mapper/entity/TRole.java new file mode 100644 index 0000000..e461125 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TRole.java @@ -0,0 +1,77 @@ +package com.mixi.mapper.entity; + + +import java.util.Date; +import java.io.Serializable; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + *

+ * 角色表 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("t_role") +public class TRole implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + /** + * 角色名 + */ + private String name; + /** + * 角色对应的菜单信息,包括操作层面 json存在 + */ + @TableField("resource_info") + private String resourceInfo; + /** + * 创建时间 + */ + @TableField("create_date") + private Date createDate; + /** + * 更新时间 + */ + @TableField("update_date") + private Date updateDate; + + + /** + * ID + */ + public static final String ID = "id"; + /** + * 角色名 + */ + public static final String NAME = "name"; + /** + * 角色对应的菜单信息,包括操作层面 json存在 + */ + public static final String RESOURCE_INFO = "resource_info"; + /** + * 创建时间 + */ + public static final String CREATE_DATE = "create_date"; + /** + * 更新时间 + */ + public static final String UPDATE_DATE = "update_date"; +} diff --git a/src/main/java/com/mixi/mapper/entity/TStore.java b/src/main/java/com/mixi/mapper/entity/TStore.java new file mode 100644 index 0000000..d99a135 --- /dev/null +++ b/src/main/java/com/mixi/mapper/entity/TStore.java @@ -0,0 +1,83 @@ +package com.mixi.mapper.entity; +import java.util.Date; +import java.io.Serializable; + + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + *

+ * 店铺表 + *

+ * + * @author generate-auto + * @since 2023-03-06 + */ +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("t_store") +public class TStore implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + /** + * 店铺名 + */ + private String name; + /** + * 店铺地址 + */ + private String address; + /** + * 备注 + */ + private String remarks; + /** + * 创建时间 + */ + @TableField("create_date") + private Date createDate; + /** + * 更新时间 + */ + @TableField("update_date") + private Date updateDate; + + + /** + * ID + */ + public static final String ID = "id"; + /** + * 店铺名 + */ + public static final String NAME = "name"; + /** + * 店铺地址 + */ + public static final String ADDRESS = "address"; + /** + * 备注 + */ + public static final String REMARKS = "remarks"; + /** + * 创建时间 + */ + public static final String CREATE_DATE = "create_date"; + /** + * 更新时间 + */ + public static final String UPDATE_DATE = "update_date"; +} diff --git a/src/main/java/com/mixi/model/dto/AccountEditDTO.java b/src/main/java/com/mixi/model/dto/AccountEditDTO.java new file mode 100644 index 0000000..4156bd5 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/AccountEditDTO.java @@ -0,0 +1,67 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Data +@ApiModel("AccountEdit") +public class AccountEditDTO { + + @ApiModelProperty("用户id,新增不传 编辑传") + private String id; + /** + * 用户名 + */ + @ApiModelProperty("用户名") + @NotBlank(message = "User Name cannot be empty!") + private String userName; + /** + * 用户账户 + */ + @ApiModelProperty("用户账户") + @NotBlank(message = "Login Account cannot be empty!") + private String userAccount; + /** + * 用户手机号 + */ + @ApiModelProperty("用户手机号") + @NotBlank(message = "User Phone cannot be empty!") + private String userPhone; + /** + * 密码(用户code) MD5加密 + */ + @ApiModelProperty("密码(用户code) MD5加密") + @NotBlank(message = "Login Code cannot be empty!") + private String userPassword; + /** + * 关联的角色id ,只能一个角色 + */ + @ApiModelProperty("关联的角色id ,只能一个角色") + @NotBlank(message = "User Role cannot be empty!") + private String roleId; + /** + * 是否app用户 1是 0不是 + */ + @ApiModelProperty("是否app用户 1是 0不是") + @NotNull(message = "App User cannot be empty!") + private Integer appUser; + + @ApiModelProperty("选择的门店id list") + @NotEmpty(message = "Owner Store cannot be empty!") + private List storeIds; + /** + * 备注 + */ + @ApiModelProperty("Remarks") + private String remarks; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; +} diff --git a/src/main/java/com/mixi/model/dto/AccountEnableDTO.java b/src/main/java/com/mixi/model/dto/AccountEnableDTO.java new file mode 100644 index 0000000..607fc77 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/AccountEnableDTO.java @@ -0,0 +1,26 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +@ApiModel("AccountEnableDTO") +public class AccountEnableDTO { + + @ApiModelProperty("id") + @NotBlank(message = "id cannot be empty!") + private String id; + + @ApiModelProperty("是否启用 1 启用 0停用") + @NotNull(message = "enable cannot be empty!") + @Max(value = 1,message = "The enable value cannot exceed 1") + @Min(value = 0,message = "The enable value cannot be lower than 0") + private Integer enable; + +} diff --git a/src/main/java/com/mixi/model/dto/AccountLoginDTO.java b/src/main/java/com/mixi/model/dto/AccountLoginDTO.java new file mode 100644 index 0000000..c0a1099 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/AccountLoginDTO.java @@ -0,0 +1,21 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("登入") +public class AccountLoginDTO { + + @NotBlank(message = "User Account cannot be empty!") + @ApiModelProperty("账号") + private String userAccount; + + @NotBlank(message = "password cannot be empty!") + @ApiModelProperty("密码") + private String password; + +} diff --git a/src/main/java/com/mixi/model/dto/AccountLogoffDTO.java b/src/main/java/com/mixi/model/dto/AccountLogoffDTO.java new file mode 100644 index 0000000..7de3daa --- /dev/null +++ b/src/main/java/com/mixi/model/dto/AccountLogoffDTO.java @@ -0,0 +1,16 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("账户注销") +public class AccountLogoffDTO { + + @NotBlank(message = "用户名不能为空!") + @ApiModelProperty("用户名") + private String userName; +} diff --git a/src/main/java/com/mixi/model/dto/AccountLogoutDTO.java b/src/main/java/com/mixi/model/dto/AccountLogoutDTO.java new file mode 100644 index 0000000..b75bc0a --- /dev/null +++ b/src/main/java/com/mixi/model/dto/AccountLogoutDTO.java @@ -0,0 +1,17 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Data +@ApiModel("登出") +public class AccountLogoutDTO { + + @NotNull(message = "userId cannot be empty !") + @ApiModelProperty("userId") + private Long userId; + +} diff --git a/src/main/java/com/mixi/model/dto/AccountRegisterDTO.java b/src/main/java/com/mixi/model/dto/AccountRegisterDTO.java new file mode 100644 index 0000000..8f38f06 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/AccountRegisterDTO.java @@ -0,0 +1,25 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("账户") +public class AccountRegisterDTO { + + @NotBlank(message = "用户名不能为空!") + @ApiModelProperty("用户名") + private String userName; + + @NotBlank(message = "密码不能为空!") + @ApiModelProperty("密码") + private String password; + + @NotBlank(message = "确认密码不能为空!") + @ApiModelProperty("确认密码") + private String confirmPassword; + +} diff --git a/src/main/java/com/mixi/model/dto/AppAccountLoginDTO.java b/src/main/java/com/mixi/model/dto/AppAccountLoginDTO.java new file mode 100644 index 0000000..8072651 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/AppAccountLoginDTO.java @@ -0,0 +1,21 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("app登入") +public class AppAccountLoginDTO { + + @NotBlank(message = "User Phone cannot be empty!") + @ApiModelProperty("用户手机号") + private String userPhone; + + @NotBlank(message = "password cannot be empty!") + @ApiModelProperty("密码") + private String password; + +} diff --git a/src/main/java/com/mixi/model/dto/BatchUploadProductDTO.java b/src/main/java/com/mixi/model/dto/BatchUploadProductDTO.java new file mode 100644 index 0000000..ffeadfc --- /dev/null +++ b/src/main/java/com/mixi/model/dto/BatchUploadProductDTO.java @@ -0,0 +1,37 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; + +@Data +@ApiModel("BatchUploadProductDTO") +public class BatchUploadProductDTO { + + @NotEmpty(message = "productIds cannot be empty!") + @ApiModelProperty("上传的商品id数组") + private List productIds; + + @NotEmpty(message = "labelIds cannot be empty!") + @ApiModelProperty("标签ids 数组 选择的标签id") + private List labelIds; + +// @NotEmpty(message = "storeInfos cannot be empty!") +// @ApiModelProperty("选择的门店信息 数组") +// private List storeInfos; +// +// @NotNull(message = "Price cannot be empty!") +// @ApiModelProperty("商品价格") +// private BigDecimal price; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; + +} diff --git a/src/main/java/com/mixi/model/dto/BatchUploadProductStoreDTO.java b/src/main/java/com/mixi/model/dto/BatchUploadProductStoreDTO.java new file mode 100644 index 0000000..799e1b2 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/BatchUploadProductStoreDTO.java @@ -0,0 +1,31 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@ApiModel("BatchUploadProductStoreDTO") +public class BatchUploadProductStoreDTO { + + @NotBlank(message = "storeId cannot be empty!") + @ApiModelProperty("门店id") + private String storeId; + + @ApiModelProperty("门店名字") + private String storeName; + + @NotEmpty(message = "stock cannot be empty!") + @ApiModelProperty("门店对应库存信息,对像") + private List stock; +} diff --git a/src/main/java/com/mixi/model/dto/BatchUploadProductStoreStockDTO.java b/src/main/java/com/mixi/model/dto/BatchUploadProductStoreStockDTO.java new file mode 100644 index 0000000..3e68cee --- /dev/null +++ b/src/main/java/com/mixi/model/dto/BatchUploadProductStoreStockDTO.java @@ -0,0 +1,23 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("BatchUploadProductStoreStockDTO") +public class BatchUploadProductStoreStockDTO { + + @NotBlank(message = "size cannot be empty!") + @ApiModelProperty("码数 , XS S M L XL XLL") + private String size; + + @NotNull(message = "num cannot be empty!") + @ApiModelProperty("对应码数数量") + private Integer num; +} diff --git a/src/main/java/com/mixi/model/dto/ColumnSortDTO.java b/src/main/java/com/mixi/model/dto/ColumnSortDTO.java new file mode 100644 index 0000000..2aa903d --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ColumnSortDTO.java @@ -0,0 +1,21 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("列排序对象") +public class ColumnSortDTO implements Serializable { + + @ApiModelProperty("要排序的列 有三个 商品创建时间传->create_date ; 价格 ->price ; 总数 ->total ") + private String column; + + @ApiModelProperty("排序方式,正序-> asc 倒序 ->desc") + private String style; + +} diff --git a/src/main/java/com/mixi/model/dto/ConfirmUploadProductDTO.java b/src/main/java/com/mixi/model/dto/ConfirmUploadProductDTO.java new file mode 100644 index 0000000..10f51fd --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ConfirmUploadProductDTO.java @@ -0,0 +1,23 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +@Data +@ApiModel("ConfirmUploadProductDTO") +public class ConfirmUploadProductDTO { + + @NotBlank(message = "batchId cannot be empty!") + @ApiModelProperty("批次id") + private String batchId; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; + +} diff --git a/src/main/java/com/mixi/model/dto/CustomBuriedPointDTO.java b/src/main/java/com/mixi/model/dto/CustomBuriedPointDTO.java new file mode 100644 index 0000000..5b4606b --- /dev/null +++ b/src/main/java/com/mixi/model/dto/CustomBuriedPointDTO.java @@ -0,0 +1,36 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("CustomBuriedPointDTO") +public class CustomBuriedPointDTO { + + @NotBlank(message = "type cannot be empty") + @ApiModelProperty("埋点类型 BROWSE 浏览 PURCHASE 购买") + private String type; + +// @NotBlank(message = "customId cannot be empty") + @ApiModelProperty("客户id,客户没登入可以购买") + private String customId; + + @NotBlank(message = "accountId cannot be empty") + @ApiModelProperty("客户登入的账号id(用户)") + private String accountId; + + @NotBlank(message = "storeId cannot be empty") + @ApiModelProperty("客户登入的店铺id") + private String storeId; + + @NotBlank(message = "productId cannot be empty") + @ApiModelProperty("对应埋点的商品id") + private String productId; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; +} diff --git a/src/main/java/com/mixi/model/dto/CustomLogoutDTO.java b/src/main/java/com/mixi/model/dto/CustomLogoutDTO.java new file mode 100644 index 0000000..17e0de9 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/CustomLogoutDTO.java @@ -0,0 +1,20 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("CustomLogoutDTO") +public class CustomLogoutDTO { + + @NotBlank(message = "customId cannot be empty") + @ApiModelProperty("客户id") + private String customId; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; +} diff --git a/src/main/java/com/mixi/model/dto/CustomRegisterDTO.java b/src/main/java/com/mixi/model/dto/CustomRegisterDTO.java new file mode 100644 index 0000000..4acb4bd --- /dev/null +++ b/src/main/java/com/mixi/model/dto/CustomRegisterDTO.java @@ -0,0 +1,28 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("CustomRegisterDTO") +public class CustomRegisterDTO { + + @NotBlank(message = "phone cannot be empty") + @ApiModelProperty("客户手机号") + private String phone; + + @NotBlank(message = "accountId cannot be empty") + @ApiModelProperty("客户登入的账号id") + private String accountId; + + @NotBlank(message = "storeId cannot be empty") + @ApiModelProperty("客户登入的店铺id") + private String storeId; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; +} diff --git a/src/main/java/com/mixi/model/dto/EditProductDTO.java b/src/main/java/com/mixi/model/dto/EditProductDTO.java new file mode 100644 index 0000000..3f7b42f --- /dev/null +++ b/src/main/java/com/mixi/model/dto/EditProductDTO.java @@ -0,0 +1,60 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.AttributeVO; +import com.mixi.model.vo.PageQueryBaseVo; +import com.mixi.model.vo.ProductAssortmentVO; +import com.mixi.model.vo.ProductLabelVO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("编辑商品分页") +public class EditProductDTO extends PageQueryBaseVo { + + @ApiModelProperty("商品Id") + @NotBlank(message = "id cannot be empty!") + private String id; + + @ApiModelProperty("商品主图url") + @NotBlank(message = "Picture Url cannot be empty!") + private String pictureUrl; + + @ApiModelProperty("商品md5值") + @NotBlank(message = "md5 cannot be empty!") + private String md5; + + @NotBlank(message = "Picture Name cannot be empty!") + @ApiModelProperty("商品主图名字") + private String pictureName; + + @NotNull(message = "Price cannot be empty!") + @ApiModelProperty("商品价格") + private BigDecimal price; + + @ApiModelProperty("商品标签信息 数组") + @NotEmpty(message = "productLabelInfo cannot be empty!") + private List productLabelInfo; + + @ApiModelProperty("一级属性标签信息,里面有二级标签的和值") + @NotNull(message = "attributeItemInfo cannot be empty!") + private AttributeVO attributeItemInfo; + + @ApiModelProperty("选择的门店信息 数组") + @NotEmpty(message = "storeInfoList cannot be empty!") + private List storeInfoList; + + @ApiModelProperty("商品搭配图片 多套 数组") + private List> assortmentList; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; +} diff --git a/src/main/java/com/mixi/model/dto/EmailSendDTO.java b/src/main/java/com/mixi/model/dto/EmailSendDTO.java new file mode 100644 index 0000000..df3ec98 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/EmailSendDTO.java @@ -0,0 +1,21 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("邮箱发送") +public class EmailSendDTO { + + @NotBlank(message = "邮箱不能为空!") + @ApiModelProperty("邮箱") + private String email; + + @NotBlank(message = "操作类型不能为空!") + @ApiModelProperty("操作类型 REGISTER 注册 FORGET_PWD 忘记密码") + private String operationType; + +} diff --git a/src/main/java/com/mixi/model/dto/ExportMiTuReportDTO.java b/src/main/java/com/mixi/model/dto/ExportMiTuReportDTO.java new file mode 100644 index 0000000..2c73b61 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ExportMiTuReportDTO.java @@ -0,0 +1,12 @@ +package com.mixi.model.dto; + +import lombok.Data; + +import java.io.InputStream; + +@Data +public class ExportMiTuReportDTO { + private String ContentType; + private String ContentDisposition; + private InputStream inputStream; +} diff --git a/src/main/java/com/mixi/model/dto/FileUploadDTO.java b/src/main/java/com/mixi/model/dto/FileUploadDTO.java new file mode 100644 index 0000000..afaccda --- /dev/null +++ b/src/main/java/com/mixi/model/dto/FileUploadDTO.java @@ -0,0 +1,27 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +import javax.validation.constraints.NotNull; + +@Data +@ApiModel("文件上传") +@AllArgsConstructor +public class FileUploadDTO { + + @NotNull(message = "文件不能为空!") + private MultipartFile file; + + @ApiModelProperty("一级类型") + private String level1Type; + + @ApiModelProperty("时区") + private String timeZone; + + @ApiModelProperty("md5") + private String md5; +} diff --git a/src/main/java/com/mixi/model/dto/GenerateCollocationDataBaseDTO.java b/src/main/java/com/mixi/model/dto/GenerateCollocationDataBaseDTO.java new file mode 100644 index 0000000..3853b89 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/GenerateCollocationDataBaseDTO.java @@ -0,0 +1,19 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +@ApiModel("GenerateCollocationDataBaseDTO") +public class GenerateCollocationDataBaseDTO { + + @ApiModelProperty("传python的商品路径") + private String path; + + @ApiModelProperty("传python的商品属性Type") + private String category; + +} diff --git a/src/main/java/com/mixi/model/dto/GenerateCollocationQueryDTO.java b/src/main/java/com/mixi/model/dto/GenerateCollocationQueryDTO.java new file mode 100644 index 0000000..e81e564 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/GenerateCollocationQueryDTO.java @@ -0,0 +1,24 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Builder +@Data +@ApiModel("GenerateCollationQueryDTO") +public class GenerateCollocationQueryDTO { + + @ApiModelProperty("传python的商品id") + private String item_id; + + @ApiModelProperty("传python的商品路径") + private String path; + + @ApiModelProperty("传python的商品属性Type") + private String item_category; + +} diff --git a/src/main/java/com/mixi/model/dto/GenerateCollocationQueryNewDTO.java b/src/main/java/com/mixi/model/dto/GenerateCollocationQueryNewDTO.java new file mode 100644 index 0000000..94d64d0 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/GenerateCollocationQueryNewDTO.java @@ -0,0 +1,21 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +@Data +@ApiModel("GenerateCollationQueryDTO") +public class GenerateCollocationQueryNewDTO { + + @ApiModelProperty("传python的商品id") + private String item_name; + + @ApiModelProperty("传python的商品路径") + private String semantic_category; + + @ApiModelProperty("传python的商品属性Type") + private String image_path; + +} diff --git a/src/main/java/com/mixi/model/dto/GetRgbByHsvBatchDTO.java b/src/main/java/com/mixi/model/dto/GetRgbByHsvBatchDTO.java new file mode 100644 index 0000000..921d17b --- /dev/null +++ b/src/main/java/com/mixi/model/dto/GetRgbByHsvBatchDTO.java @@ -0,0 +1,22 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Data +@ApiModel("根据rgb数组批量获取潘通rgb") +public class GetRgbByHsvBatchDTO { + @NotNull(message = "r cannot be empty!") + @ApiModelProperty("h值") + private Integer h; + @NotNull(message = "g cannot be empty!") + @ApiModelProperty("s值") + private Integer s; + @NotNull(message = "b cannot be empty!") + @ApiModelProperty("v值") + private Integer v; + +} diff --git a/src/main/java/com/mixi/model/dto/LabelAddOrEditDTO.java b/src/main/java/com/mixi/model/dto/LabelAddOrEditDTO.java new file mode 100644 index 0000000..801016c --- /dev/null +++ b/src/main/java/com/mixi/model/dto/LabelAddOrEditDTO.java @@ -0,0 +1,38 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("LabelAddOrEditDTO") +public class LabelAddOrEditDTO { + + @ApiModelProperty("新增不传 编辑传") + private String id; + + /** + * 标签名 + */ + @NotBlank(message = "Label Name cannot be empty") + @ApiModelProperty("标签名称") + private String name; + /** + * 标签类型 + */ + @NotBlank(message = "Label type cannot be empty") + @ApiModelProperty("标签类型 CUSTOM ->自定义标签 ,NEW_PRODUCT ->新品 SALE ->折扣") + private String type; + /** + * 备注 + */ + @ApiModelProperty("Remarks") + private String remarks; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; + +} diff --git a/src/main/java/com/mixi/model/dto/NoteSendDTO.java b/src/main/java/com/mixi/model/dto/NoteSendDTO.java new file mode 100644 index 0000000..2d2e7ca --- /dev/null +++ b/src/main/java/com/mixi/model/dto/NoteSendDTO.java @@ -0,0 +1,25 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("短信发送") +public class NoteSendDTO { + + @NotBlank(message = " 手机[区域/国家]号不能为空!") + @ApiModelProperty("[区域/国家]号 示例如 852 香港 不支持中国") + private String regionNum; + + @NotBlank(message = "手机号不能为空!") + @ApiModelProperty("手机号") + private String phone; + + @NotBlank(message = "操作类型不能为空!") + @ApiModelProperty("操作类型 LOGIN 登入 FORGET_PWD 忘记密码") + private String operationType; + +} diff --git a/src/main/java/com/mixi/model/dto/ProductColorDTO.java b/src/main/java/com/mixi/model/dto/ProductColorDTO.java new file mode 100644 index 0000000..b28c118 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ProductColorDTO.java @@ -0,0 +1,23 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.AppProductColorExtractVO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.List; + +@Data +@ApiModel("颜色识别") +public class ProductColorDTO implements Serializable { + + @ApiModelProperty("商品主色 RGB 值 数组") + @Size(min = 1,max = 5,message = "Rgb size must be 1 to 5 !") + @NotEmpty(message = "productRgbList cannot be empty!") + private List productRgbList; + +} diff --git a/src/main/java/com/mixi/model/dto/ProductColorExtratDTO.java b/src/main/java/com/mixi/model/dto/ProductColorExtratDTO.java new file mode 100644 index 0000000..2fd8e03 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ProductColorExtratDTO.java @@ -0,0 +1,21 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +@AllArgsConstructor +@NoArgsConstructor +@Data +@ApiModel("主色提取") +public class ProductColorExtratDTO implements Serializable { + + @ApiModelProperty("商品上传路径") + @NotBlank(message = "pictureUrl cannot be empty!") + private String pictureUrl; + +} diff --git a/src/main/java/com/mixi/model/dto/ProductExportDTO.java b/src/main/java/com/mixi/model/dto/ProductExportDTO.java new file mode 100644 index 0000000..26a01af --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ProductExportDTO.java @@ -0,0 +1,39 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("商品导出") +public class ProductExportDTO implements Serializable { + + @ApiModelProperty("商品标签名Id数组") + private List productLabelIds; + + @ApiModelProperty("商品一级标签类型 top dress 等等") + private String labelItem; + + @ApiModelProperty("商品二级标签类型及对应标签map") + private Map> labelTypeMap; + + @ApiModelProperty("Add time start") + private Long createDateStart; + + @ApiModelProperty("Add time end") + private Long createDateEnd; + + @ApiModelProperty("上架状态 0下架 1上架") + private Integer onSaleState; + + @ApiModelProperty("商品店铺id数组") + private List storeIds; + + @ApiModelProperty("降序排列字段数组 ") + private List columnSortList; + +} diff --git a/src/main/java/com/mixi/model/dto/ProductOnSaleDTO.java b/src/main/java/com/mixi/model/dto/ProductOnSaleDTO.java new file mode 100644 index 0000000..9eee769 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ProductOnSaleDTO.java @@ -0,0 +1,26 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +@ApiModel("ProductOnSaleDTO") +public class ProductOnSaleDTO { + + @ApiModelProperty("id") + @NotBlank(message = "id cannot be empty!") + private String id; + + @ApiModelProperty("是否启用 1 上架 0下架") + @NotNull(message = "onSaleState cannot be empty!") + @Max(value = 1,message = "The onSaleState value cannot exceed 1") + @Min(value = 0,message = "The onSaleState value cannot be lower than 0") + private Integer onSaleState; + +} diff --git a/src/main/java/com/mixi/model/dto/ProductProcessDTO.java b/src/main/java/com/mixi/model/dto/ProductProcessDTO.java new file mode 100644 index 0000000..10a4922 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ProductProcessDTO.java @@ -0,0 +1,42 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@ApiModel("ProductProcessDTO") +public class ProductProcessDTO { + + @ApiModelProperty("总商品数") + private Integer total; + + @ApiModelProperty("已上传的商品数") + private Integer hasUpload; + + @ApiModelProperty("上传类型 Attribute -> 属性 Collocation ->搭配 ") + private String uploadType; + + @ApiModelProperty("上传总状态 1完成 0未完成 2未上传") + private Integer status; + + @ApiModelProperty("进度百分比") + private BigDecimal process; + + public ProductProcessDTO(Integer total, Integer hasUpload, String uploadType, Integer status) { + this.total = total; + this.hasUpload = hasUpload; + this.uploadType = uploadType; + this.status = status; + } +} diff --git a/src/main/java/com/mixi/model/dto/ProductSimilaDTO.java b/src/main/java/com/mixi/model/dto/ProductSimilaDTO.java new file mode 100644 index 0000000..fa6f4a0 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/ProductSimilaDTO.java @@ -0,0 +1,23 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +@Data +@ApiModel("相识度识别") +public class ProductSimilaDTO implements Serializable { + +// @ApiModelProperty("商品id") +// @NotBlank(message = "productId cannot be empty!") +// private String productId; + + @ApiModelProperty("图片上传路径") + @NotBlank(message = "pictureUrl cannot be empty!") + private String pictureUrl; + +} diff --git a/src/main/java/com/mixi/model/dto/QueryAccountPageDTO.java b/src/main/java/com/mixi/model/dto/QueryAccountPageDTO.java new file mode 100644 index 0000000..23c02e2 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryAccountPageDTO.java @@ -0,0 +1,30 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel("查询用户账户分页") +public class QueryAccountPageDTO extends PageQueryBaseVo { + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("用户手机号") + private String userPhone; + + @ApiModelProperty("角色id") + private String roleId; + + @ApiModelProperty("启用状态 1启用中 0已停用") + private Integer state; + + @ApiModelProperty("创建时间-开始") + private Long createDateStart; + + @ApiModelProperty("创建时间-结束") + private Long createDateEnd; + +} diff --git a/src/main/java/com/mixi/model/dto/QueryLabelPageDTO.java b/src/main/java/com/mixi/model/dto/QueryLabelPageDTO.java new file mode 100644 index 0000000..bf23f44 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryLabelPageDTO.java @@ -0,0 +1,24 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel("查询标签分页") +public class QueryLabelPageDTO extends PageQueryBaseVo { + + @ApiModelProperty("Label name") + private String name; + + @ApiModelProperty("Label type - > CUSTOM , NEW_PRODUCT , SALE ") + private String type; + + @ApiModelProperty("Add time start") + private Long createDateStart; + + @ApiModelProperty("Add time end") + private Long createDateEnd; + +} diff --git a/src/main/java/com/mixi/model/dto/QueryMiTuExportPageDTO.java b/src/main/java/com/mixi/model/dto/QueryMiTuExportPageDTO.java new file mode 100644 index 0000000..8917387 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryMiTuExportPageDTO.java @@ -0,0 +1,20 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@ApiModel("查询标签分页") +public class QueryMiTuExportPageDTO extends PageQueryBaseVo { + + private String fileName; + private String span; + private LocalDateTime startTime; + private LocalDateTime endTime; + + +} \ No newline at end of file diff --git a/src/main/java/com/mixi/model/dto/QueryNewProductPageDTO.java b/src/main/java/com/mixi/model/dto/QueryNewProductPageDTO.java new file mode 100644 index 0000000..ef7936a --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryNewProductPageDTO.java @@ -0,0 +1,23 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("查询新品推荐列表") +public class QueryNewProductPageDTO extends PageQueryBaseVo implements Serializable { + + @ApiModelProperty("店铺id") + @NotBlank(message = "storeId cannot be empty!") + private String storeId; + + @ApiModelProperty("商品一级标签类型 top dress 等等") + private String labelItem; +} diff --git a/src/main/java/com/mixi/model/dto/QueryProductAssortmentPageDTO.java b/src/main/java/com/mixi/model/dto/QueryProductAssortmentPageDTO.java new file mode 100644 index 0000000..03a0117 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryProductAssortmentPageDTO.java @@ -0,0 +1,24 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("QueryProductAssortmentPageDTO") +public class QueryProductAssortmentPageDTO extends PageQueryBaseVo { + + @ApiModelProperty("商品一级标签类型 top dress 等等") + private String LabelItem; + + @ApiModelProperty("商品二级标签类型及对应标签map") + private Map> LabelTypeMap; + + @ApiModelProperty("搭配id 数组") + private List assortmentIdList; + +} diff --git a/src/main/java/com/mixi/model/dto/QueryProductPageDTO.java b/src/main/java/com/mixi/model/dto/QueryProductPageDTO.java new file mode 100644 index 0000000..057ae96 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryProductPageDTO.java @@ -0,0 +1,40 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("查询商品分页") +public class QueryProductPageDTO extends PageQueryBaseVo implements Serializable { + + @ApiModelProperty("商品标签名Id数组") + private List productLabelIds; + + @ApiModelProperty("商品一级标签类型 top dress 等等") + private String labelItem; + + @ApiModelProperty("商品二级标签类型及对应标签map") + private Map> labelTypeMap; + + @ApiModelProperty("Add time start") + private Long createDateStart; + + @ApiModelProperty("Add time end") + private Long createDateEnd; + + @ApiModelProperty("上架状态 0下架 1上架") + private Integer onSaleState; + + @ApiModelProperty("商品店铺id数组") + private List storeIds; + + @ApiModelProperty("降序排列字段数组 ") + private List columnSortList; + +} diff --git a/src/main/java/com/mixi/model/dto/QueryProductRankDTO.java b/src/main/java/com/mixi/model/dto/QueryProductRankDTO.java new file mode 100644 index 0000000..a9d5254 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryProductRankDTO.java @@ -0,0 +1,26 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +@Data +@ApiModel("查询销量排行列表") +public class QueryProductRankDTO implements Serializable { + + @ApiModelProperty("店铺id") + @NotBlank(message = "storeId cannot be empty!") + private String storeId; + + @ApiModelProperty("销量排行开始时间") + @NotNull(message = "createDateStart cannot be empty!") + private Long createDateStart; + + @ApiModelProperty("销量排行结束时间") + @NotNull(message = "createDateEnd cannot be empty!") + private Long createDateEnd; +} diff --git a/src/main/java/com/mixi/model/dto/QueryRecommendPageDTO.java b/src/main/java/com/mixi/model/dto/QueryRecommendPageDTO.java new file mode 100644 index 0000000..e887cd8 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryRecommendPageDTO.java @@ -0,0 +1,18 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +@Data +@ApiModel("查询个性化推荐列表") +public class QueryRecommendPageDTO extends PageQueryBaseVo implements Serializable { + + @ApiModelProperty("商品一级标签类型 top dress 等等") + private String labelItem; + +} diff --git a/src/main/java/com/mixi/model/dto/QueryStorePageDTO.java b/src/main/java/com/mixi/model/dto/QueryStorePageDTO.java new file mode 100644 index 0000000..c43317f --- /dev/null +++ b/src/main/java/com/mixi/model/dto/QueryStorePageDTO.java @@ -0,0 +1,15 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel("名字分页") +public class QueryStorePageDTO extends PageQueryBaseVo { + + @ApiModelProperty("Store name") + private String name; + +} diff --git a/src/main/java/com/mixi/model/dto/RoleAddOrEditDTO.java b/src/main/java/com/mixi/model/dto/RoleAddOrEditDTO.java new file mode 100644 index 0000000..e35465b --- /dev/null +++ b/src/main/java/com/mixi/model/dto/RoleAddOrEditDTO.java @@ -0,0 +1,30 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.RolePermissionVO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +@ApiModel("RoleAddOrEditDTO") +public class RoleAddOrEditDTO { + + @ApiModelProperty("新增不传 编辑传") + private String id; + + @NotBlank(message = "Role Name cannot be empty") + @ApiModelProperty("角色名") + private String name; + + @NotNull(message = "Role Permission cannot be empty") + @ApiModelProperty("角色菜单权限") + private RolePermissionVO rolePermission; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; + +} diff --git a/src/main/java/com/mixi/model/dto/SearchProductPageDTO.java b/src/main/java/com/mixi/model/dto/SearchProductPageDTO.java new file mode 100644 index 0000000..aa5ded8 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/SearchProductPageDTO.java @@ -0,0 +1,27 @@ +package com.mixi.model.dto; + +import com.mixi.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +@Data +@ApiModel("检索商品分页列表") +public class SearchProductPageDTO extends PageQueryBaseVo implements Serializable { + + @ApiModelProperty("店铺id") + @NotBlank(message = "storeId cannot be empty!") + private String storeId; + + @ApiModelProperty("商品一级标签类型 top dress 等等") + private String labelItem; + + @ApiModelProperty("商品二级标签类型及对应标签map") + private Map> labelTypeMap; + +} diff --git a/src/main/java/com/mixi/model/dto/StoreAddOrEditDTO.java b/src/main/java/com/mixi/model/dto/StoreAddOrEditDTO.java new file mode 100644 index 0000000..98fb242 --- /dev/null +++ b/src/main/java/com/mixi/model/dto/StoreAddOrEditDTO.java @@ -0,0 +1,38 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("StoreAddOrEditDTO") +public class StoreAddOrEditDTO { + + @ApiModelProperty("新增不传 编辑传") + private String id; + + /** + * 店铺名 + */ + @NotBlank(message = "Store name cannot be empty") + @ApiModelProperty("Store Name") + private String name; + /** + * 店铺地址 + */ + @NotBlank(message = "Store address cannot be empty") + @ApiModelProperty("Store Adress") + private String address; + /** + * 备注 + */ + @ApiModelProperty("Remarks") + private String remarks; + + @NotBlank(message = "timeZone cannot be empty!") + @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") + private String timeZone; + +} diff --git a/src/main/java/com/mixi/model/dto/StoreDeleteDTO.java b/src/main/java/com/mixi/model/dto/StoreDeleteDTO.java new file mode 100644 index 0000000..df1ed4b --- /dev/null +++ b/src/main/java/com/mixi/model/dto/StoreDeleteDTO.java @@ -0,0 +1,17 @@ +package com.mixi.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("DeleteDTO") +public class StoreDeleteDTO { + + @ApiModelProperty("ID") + @NotBlank(message = "id cannot be empty!") + private String id; + +} diff --git a/src/main/java/com/mixi/model/main b/src/main/java/com/mixi/model/main new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/com/mixi/model/vo/AccountLoginVO.java b/src/main/java/com/mixi/model/vo/AccountLoginVO.java new file mode 100644 index 0000000..ac5a2f9 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AccountLoginVO.java @@ -0,0 +1,23 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("登入-响应") +public class AccountLoginVO { + + @ApiModelProperty("token") + private String token; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户名") + private String userName; + +} diff --git a/src/main/java/com/mixi/model/vo/AccountVO.java b/src/main/java/com/mixi/model/vo/AccountVO.java new file mode 100644 index 0000000..12d6e9f --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AccountVO.java @@ -0,0 +1,59 @@ +package com.mixi.model.vo; + +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +@ApiModel("用户-响应") +public class AccountVO { + + @ApiModelProperty("用户id") + private Long id; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("用户账户") + private String userAccount; + + @ApiModelProperty("用户手机号") + private String userPhone; + + @ApiModelProperty("关联的角色id ,只能一个角色") + private Long roleId; + + @ApiModelProperty("关联的角色名称") + private String roleName; + + @ApiModelProperty("关联的店铺ids") + private List storeIds; + + @ApiModelProperty("关联的店铺名称") + private List storeName; + + @ApiModelProperty("是否app用户 1是 0不是") + private Integer appUser; + + @ApiModelProperty("是否app用户字符 Yes No") + private String appUserName; + + @ApiModelProperty("启用状态 1启用中 0已停用") + private Integer state; + + @ApiModelProperty("密码 base64加密") + private String userPassword; + + @ApiModelProperty("启用状态中文") + private String stateName; + + @ApiModelProperty("备注") + private String remarks; + + @ApiModelProperty("创建时间") + private Long createDate; +} diff --git a/src/main/java/com/mixi/model/vo/AllRoleVO.java b/src/main/java/com/mixi/model/vo/AllRoleVO.java new file mode 100644 index 0000000..b52af5a --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AllRoleVO.java @@ -0,0 +1,22 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel("所有角色分页-响应") +public class AllRoleVO { + + /** + * ID + */ + @ApiModelProperty("角色id") + private String id; + + /** + * 角色名称 + */ + @ApiModelProperty("角色名称") + private String name; +} diff --git a/src/main/java/com/mixi/model/vo/AppAccountLoginVO.java b/src/main/java/com/mixi/model/vo/AppAccountLoginVO.java new file mode 100644 index 0000000..9e3eca6 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AppAccountLoginVO.java @@ -0,0 +1,28 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel("app登入-响应") +public class AppAccountLoginVO { + + @ApiModelProperty("token") + private String token; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("用户手机号") + private String userPhone; + + @ApiModelProperty("用户门店信息") + private List storeList; + +} diff --git a/src/main/java/com/mixi/model/vo/AppNewProductVO.java b/src/main/java/com/mixi/model/vo/AppNewProductVO.java new file mode 100644 index 0000000..30151bb --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AppNewProductVO.java @@ -0,0 +1,32 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@ApiModel("App新品推荐分页-响应") +public class AppNewProductVO { + + @ApiModelProperty("商品Id") + private String id; + + @ApiModelProperty("商品主图url") + private String pictureUrl; + + @ApiModelProperty("商品标签信息 数组") + private List productLabelInfo; + + @ApiModelProperty("商品价格,港币(前端写死)") + private BigDecimal price; + + @ApiModelProperty("颜色,pantone值") + private String color; + + @ApiModelProperty("颜色,rgb值,下划线分割") + private String rgb; + +} diff --git a/src/main/java/com/mixi/model/vo/AppProductColorExtractVO.java b/src/main/java/com/mixi/model/vo/AppProductColorExtractVO.java new file mode 100644 index 0000000..03df280 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AppProductColorExtractVO.java @@ -0,0 +1,29 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; + +@AllArgsConstructor +@NoArgsConstructor +@Data +@ApiModel("App RGB值") +public class AppProductColorExtractVO { + + @ApiModelProperty("主色的r值") + @NotBlank(message = "r value cannot be empty!") + private String r; + + @ApiModelProperty("主色的g值") + @NotBlank(message = "g value cannot be empty!") + private String g; + + @ApiModelProperty("主色的b值") + @NotBlank(message = "b value cannot be empty!") + private String b; + +} diff --git a/src/main/java/com/mixi/model/vo/AppProductSaleRankVO.java b/src/main/java/com/mixi/model/vo/AppProductSaleRankVO.java new file mode 100644 index 0000000..3a475fe --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AppProductSaleRankVO.java @@ -0,0 +1,34 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@ApiModel("App商品销量排行-响应") +public class AppProductSaleRankVO { + + @ApiModelProperty("商品Id") + private String id; + + @ApiModelProperty("商品主图url") + private String pictureUrl; + + @ApiModelProperty("售出总数") + private String total; + + @ApiModelProperty("商品标签信息 数组") + private List productLabelInfo; + + @ApiModelProperty("商品价格,港币(前端写死)") + private BigDecimal price; + + @ApiModelProperty("颜色,pantone值") + private String color; + + @ApiModelProperty("颜色,rgb值,下划线分割") + private String rgb; +} diff --git a/src/main/java/com/mixi/model/vo/AppProductSingleUploadVo.java b/src/main/java/com/mixi/model/vo/AppProductSingleUploadVo.java new file mode 100644 index 0000000..891d420 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AppProductSingleUploadVo.java @@ -0,0 +1,38 @@ +package com.mixi.model.vo; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.io.Serializable; + +/** + *

+ * 商品表上传vo + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "AppProductSingleUploadVo") +public class AppProductSingleUploadVo implements Serializable { + + private static final long serialVersionUID = 1L; + @ApiModelProperty("文件主图url") + private String pictureUrl; + + @ApiModelProperty("文件名") + private String pictureName; + + @ApiModelProperty("文件md5值,去重用") + private String md5; + +} diff --git a/src/main/java/com/mixi/model/vo/AttributeTypeVO.java b/src/main/java/com/mixi/model/vo/AttributeTypeVO.java new file mode 100644 index 0000000..c0c9802 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AttributeTypeVO.java @@ -0,0 +1,22 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel("属性值类型-响应") +public class AttributeTypeVO { + + @ApiModelProperty(" Id") + private String id; + + @ApiModelProperty("Label Type 每个label_item 对应不同的attribute") + private String labelType; + + @ApiModelProperty("属性值") + private List attributeValueList; + +} diff --git a/src/main/java/com/mixi/model/vo/AttributeVO.java b/src/main/java/com/mixi/model/vo/AttributeVO.java new file mode 100644 index 0000000..85c8bac --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AttributeVO.java @@ -0,0 +1,26 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel("属性值-响应") +public class AttributeVO { + + @ApiModelProperty("Label Item 包括 Top Shoes Dress Jumpsuit Coat Outwear") + private String labelItem; + + @ApiModelProperty("Label Type 对应的值") + private List labelTypeValueList; + + @ApiModelProperty("Label Type 数组") + private List attributeTypeList; + +} diff --git a/src/main/java/com/mixi/model/vo/AttributeValueVO.java b/src/main/java/com/mixi/model/vo/AttributeValueVO.java new file mode 100644 index 0000000..63f1aff --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AttributeValueVO.java @@ -0,0 +1,23 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@ApiModel("属性值1-响应") +public class AttributeValueVO { + + @ApiModelProperty("属性类型id") + private String attributeTypeId; + + @ApiModelProperty("属性值") + private String attributeValue; + +} diff --git a/src/main/java/com/mixi/model/vo/AuthPrincipalVo.java b/src/main/java/com/mixi/model/vo/AuthPrincipalVo.java new file mode 100644 index 0000000..54b29a3 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/AuthPrincipalVo.java @@ -0,0 +1,60 @@ +package com.mixi.model.vo; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +public class AuthPrincipalVo implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 用户名 + */ + private String username; + + /** + * 用户账户 + */ + private String userAccount; + + /** + * 头像 + */ + private String avatarUrl; + + /** + * 是否为管理员(1是 0否) + */ + private Boolean isAdmin; + + /** + * 来源 + */ + private String source; + + /** + * 状态 + */ + private Integer status; + + /** + * 角色 + */ +// private List roles; + + /** + * 角色部门 + */ +// private List depts; + /** + * 角色权限 + */ + private List authorities; +} diff --git a/src/main/java/com/mixi/model/vo/CountWorkBentchVO.java b/src/main/java/com/mixi/model/vo/CountWorkBentchVO.java new file mode 100644 index 0000000..9ca9395 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/CountWorkBentchVO.java @@ -0,0 +1,34 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +@ApiModel("工作台统计-响应") +public class CountWorkBentchVO { + + @ApiModelProperty("门店数") + private String storeCount; + + @ApiModelProperty("上架商品数") + private String onSaleProductCount; + + @ApiModelProperty("订单成交量") + private String orderSuccessCount; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("角色名") + private String roleName; + + @ApiModelProperty("店铺名") + private String storeName; + + @ApiModelProperty("店铺地址") + private String storeAddress; + +} diff --git a/src/main/java/com/mixi/model/vo/CustomRegisterVO.java b/src/main/java/com/mixi/model/vo/CustomRegisterVO.java new file mode 100644 index 0000000..7dd5722 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/CustomRegisterVO.java @@ -0,0 +1,20 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@ApiModel("客户登入-响应") +public class CustomRegisterVO { + + @ApiModelProperty("客户id") + private String id; + + @ApiModelProperty("客户手机号") + private String phone; +} diff --git a/src/main/java/com/mixi/model/vo/FileVO.java b/src/main/java/com/mixi/model/vo/FileVO.java new file mode 100644 index 0000000..75034e9 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/FileVO.java @@ -0,0 +1,19 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; + +@AllArgsConstructor +@Data +@ApiModel("登入-响应") +public class FileVO { + + @ApiModelProperty("高度") + private Integer high; + + @ApiModelProperty("宽度") + private Integer width; + +} diff --git a/src/main/java/com/mixi/model/vo/GenerateCollocationOutVO.java b/src/main/java/com/mixi/model/vo/GenerateCollocationOutVO.java new file mode 100644 index 0000000..0fab74d --- /dev/null +++ b/src/main/java/com/mixi/model/vo/GenerateCollocationOutVO.java @@ -0,0 +1,20 @@ +package com.mixi.model.vo; + +import com.mixi.model.dto.GenerateCollocationQueryNewDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel("GenerateCollocationDataBaseVO") +public class GenerateCollocationOutVO { + + @ApiModelProperty("输出的商品搭配") + private List> outfits; + + @ApiModelProperty("传python的商品id") + private List scores; + +} diff --git a/src/main/java/com/mixi/model/vo/LabelVO.java b/src/main/java/com/mixi/model/vo/LabelVO.java new file mode 100644 index 0000000..76ea082 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/LabelVO.java @@ -0,0 +1,47 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel("标签分页-响应") +public class LabelVO { + + /** + * ID + */ + @ApiModelProperty("Store Id") + private String id; + + /** + * 标签名称 + */ + @ApiModelProperty("Label Name") + private String name; + /** + * 标签类型 + */ + @ApiModelProperty("Label Type") + private String type; + /** + * 备注 + */ + @ApiModelProperty("remarks") + private String remarks; + /** + * 创建时间 + */ + @ApiModelProperty("Add Time") + private Long createDate; + /** + * 创建用户 + */ + @ApiModelProperty("Add User") + private String createUserName; + /** + * 打标签商品数 + */ + @ApiModelProperty("Label Product Counts") + private Integer counts; +} diff --git a/src/main/java/com/mixi/model/vo/PageQueryBaseVo.java b/src/main/java/com/mixi/model/vo/PageQueryBaseVo.java new file mode 100644 index 0000000..ed10fb7 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/PageQueryBaseVo.java @@ -0,0 +1,23 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; + + +@Data +@ApiModel("分页查询") +public class PageQueryBaseVo { + + @ApiModelProperty("页码") + @Min(value = 0, message = "page最小值为1") + private Integer page = 1; + + @ApiModelProperty("每页数量") + @Min(value = 0, message = "size最小值为1") + @Max(value = 50, message = "size最大值为50") + private Integer size = 20; +} diff --git a/src/main/java/com/mixi/model/vo/PantoneVO.java b/src/main/java/com/mixi/model/vo/PantoneVO.java new file mode 100644 index 0000000..aaaf55a --- /dev/null +++ b/src/main/java/com/mixi/model/vo/PantoneVO.java @@ -0,0 +1,44 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +@ApiModel("潘通-响应") +public class PantoneVO { + + @ApiModelProperty("id") + private Integer id; + + @ApiModelProperty("名字") + private String name; + + @ApiModelProperty("tcx值") + private String tcx; + + @ApiModelProperty("r") + private Integer r; + + @ApiModelProperty("r") + private Integer g; + + @ApiModelProperty("r") + private Integer b; + + @ApiModelProperty("h") + private Integer h; + + @ApiModelProperty("s") + private Integer s; + + @ApiModelProperty("v") + private Integer v; + + public PantoneVO(String name, String tcx) { + this.name = name; + this.tcx = tcx; + } +} diff --git a/src/main/java/com/mixi/model/vo/ProductAssortmentInnerVO.java b/src/main/java/com/mixi/model/vo/ProductAssortmentInnerVO.java new file mode 100644 index 0000000..93646df --- /dev/null +++ b/src/main/java/com/mixi/model/vo/ProductAssortmentInnerVO.java @@ -0,0 +1,22 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@ApiModel("ProductAssortmentInnerVO") +public class ProductAssortmentInnerVO { + + @ApiModelProperty("商品Id") + private String productId; + + @ApiModelProperty("商品主图url") + private String pictureUrl; + + @ApiModelProperty("商品价格,港币(前端写死)") + private BigDecimal price; + +} diff --git a/src/main/java/com/mixi/model/vo/ProductAssortmentVO.java b/src/main/java/com/mixi/model/vo/ProductAssortmentVO.java new file mode 100644 index 0000000..2be029d --- /dev/null +++ b/src/main/java/com/mixi/model/vo/ProductAssortmentVO.java @@ -0,0 +1,24 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +@ApiModel("ProductAssortmentVO") +public class ProductAssortmentVO { + + @ApiModelProperty("搭配id") + private Long id; + + @ApiModelProperty("生成的搭配图地址") + private String generatePictureUrl; + + @ApiModelProperty("搭配的商品id") + private Long productId; + + @ApiModelProperty("搭配的商品价格") + private BigDecimal price; +} diff --git a/src/main/java/com/mixi/model/vo/ProductLabelVO.java b/src/main/java/com/mixi/model/vo/ProductLabelVO.java new file mode 100644 index 0000000..1caccfc --- /dev/null +++ b/src/main/java/com/mixi/model/vo/ProductLabelVO.java @@ -0,0 +1,27 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel("商品标签VO") +public class ProductLabelVO { + + /** + * ID + */ + @ApiModelProperty("Label Id") + private String id; + + /** + * 标签名称 + */ + @ApiModelProperty("Label Name") + private String name; + /** + * 标签类型 + */ + @ApiModelProperty("Label Type") + private String type; +} diff --git a/src/main/java/com/mixi/model/vo/ProductVO.java b/src/main/java/com/mixi/model/vo/ProductVO.java new file mode 100644 index 0000000..2503d31 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/ProductVO.java @@ -0,0 +1,64 @@ +package com.mixi.model.vo; + +import com.mixi.model.dto.BatchUploadProductStoreDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.math.BigDecimal; +import java.util.List; + +@Data +@ApiModel("商品分页-响应") +public class ProductVO { + + @ApiModelProperty("商品Id") + private String id; + + @ApiModelProperty("商品批次id") + private String batchId; + + @ApiModelProperty("商品主图url") + private String pictureUrl; + + @ApiModelProperty("商品主图名字") + private String pictureName; + + @ApiModelProperty("商品总数") + private Integer total; + + @ApiModelProperty("商品状态 1上架 0下架") + private Integer onSaleState; + + @ApiModelProperty("商品状态中文 1上架 0下架") + private String onSaleStateName; + + @ApiModelProperty("Add Time") + private Long createDate; + + @ApiModelProperty("商品价格,港币(前端写死)") + private BigDecimal price; + + @ApiModelProperty("颜色,pantone值") + private String color; + + @ApiModelProperty("颜色,rgb值,下划线分割") + private String rgb; + + @ApiModelProperty("商品md5值") + private String md5; + + @ApiModelProperty("商品标签信息 数组") + private List productLabelInfo; + + @ApiModelProperty("一级属性标签信息,里面有二级标签的和值") + private AttributeVO attributeItemInfo; + + @ApiModelProperty("选择的门店信息 数组") + private List storeInfoList; + + @ApiModelProperty("商品搭配图片 多套 数组") + private List> assortmentList; + +} diff --git a/src/main/java/com/mixi/model/vo/ReLoginVO.java b/src/main/java/com/mixi/model/vo/ReLoginVO.java new file mode 100644 index 0000000..8e275af --- /dev/null +++ b/src/main/java/com/mixi/model/vo/ReLoginVO.java @@ -0,0 +1,22 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; + +@AllArgsConstructor +@Data +@ApiModel("刷新token-响应") +public class ReLoginVO { + + @ApiModelProperty("token") + private String token; + + @ApiModelProperty("用户id") + private String userId; + + @ApiModelProperty("用户名") + private String userName; + +} diff --git a/src/main/java/com/mixi/model/vo/RolePermission1VO.java b/src/main/java/com/mixi/model/vo/RolePermission1VO.java new file mode 100644 index 0000000..b9fbd50 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/RolePermission1VO.java @@ -0,0 +1,28 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel("角色权限1-响应") +public class RolePermission1VO { + + + @ApiModelProperty("一级菜单code") + private String code; + + @ApiModelProperty("一级菜单") + private String resource; + + @ApiModelProperty("0 未选中 1选中") + private Integer select; + + @ApiModelProperty("顺序") + private Integer sort; + + @ApiModelProperty("二级菜单 list") + private List level2ResourceList; +} diff --git a/src/main/java/com/mixi/model/vo/RolePermission2OperationVO.java b/src/main/java/com/mixi/model/vo/RolePermission2OperationVO.java new file mode 100644 index 0000000..9f4e0b2 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/RolePermission2OperationVO.java @@ -0,0 +1,32 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Data +@ApiModel("角色权限2操作-响应") +public class RolePermission2OperationVO { + + + @ApiModelProperty("二级菜单code") + private String code; + + @ApiModelProperty("二级菜单") + private String resource; + + @ApiModelProperty("0 未选中 1选中") + private Integer select; + + @ApiModelProperty("顺序") + private Integer sort; + +} diff --git a/src/main/java/com/mixi/model/vo/RolePermission2VO.java b/src/main/java/com/mixi/model/vo/RolePermission2VO.java new file mode 100644 index 0000000..9f7d0a9 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/RolePermission2VO.java @@ -0,0 +1,28 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel("角色权限2-响应") +public class RolePermission2VO { + + + @ApiModelProperty("二级菜单code") + private String code; + + @ApiModelProperty("二级菜单") + private String resource; + + @ApiModelProperty("0 未选中 1选中") + private Integer select; + + @ApiModelProperty("顺序") + private Integer sort; + + @ApiModelProperty("二级操作 list ") + private List operationList; +} diff --git a/src/main/java/com/mixi/model/vo/RolePermissionVO.java b/src/main/java/com/mixi/model/vo/RolePermissionVO.java new file mode 100644 index 0000000..db10cd3 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/RolePermissionVO.java @@ -0,0 +1,18 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel("角色权限-响应") +public class RolePermissionVO { + + @ApiModelProperty("是否选中所有 0未选中 1选中") + private Integer allSelect; + + @ApiModelProperty("一级菜单 list") + private List level1ResourceList; +} diff --git a/src/main/java/com/mixi/model/vo/RoleVO.java b/src/main/java/com/mixi/model/vo/RoleVO.java new file mode 100644 index 0000000..bb805f3 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/RoleVO.java @@ -0,0 +1,29 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +@ApiModel("角色分页-响应") +public class RoleVO { + + /** + * ID + */ + @ApiModelProperty("角色id") + private String id; + + /** + * 角色名称 + */ + @ApiModelProperty("角色名称") + private String name; + /** + * 角色权限 + */ + @ApiModelProperty("角色菜单权限") + private RolePermissionVO rolePermission; +} diff --git a/src/main/java/com/mixi/model/vo/StoreVO.java b/src/main/java/com/mixi/model/vo/StoreVO.java new file mode 100644 index 0000000..b16469d --- /dev/null +++ b/src/main/java/com/mixi/model/vo/StoreVO.java @@ -0,0 +1,37 @@ +package com.mixi.model.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +@Data +@ApiModel("门店-响应") +public class StoreVO { + + /** + * ID + */ + @ApiModelProperty("Store Id") + private String id; + /** + * 店铺名 + */ + @ApiModelProperty("Store Name") + private String name; + /** + * 店铺地址 + */ + @ApiModelProperty("Store Adress") + private String address; + /** + * 备注 + */ + @ApiModelProperty("Remarks") + private String remarks; + /** + * 创建时间 + */ + @ApiModelProperty("Add Time") + private Long createDate; + +} diff --git a/src/main/java/com/mixi/model/vo/TProductBatchUploadRelationVo.java b/src/main/java/com/mixi/model/vo/TProductBatchUploadRelationVo.java new file mode 100644 index 0000000..cbdeca4 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/TProductBatchUploadRelationVo.java @@ -0,0 +1,39 @@ +package com.mixi.model.vo; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; +import java.util.List; + +/** + *

+ * 商品表上传vo + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Getter +@Setter +@ApiModel(value = "TProductBatchUploadRelationVo") +public class TProductBatchUploadRelationVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("账户id") + private Long accountId; + + @ApiModelProperty("商品批次id") + private Long batchId; + + @ApiModelProperty("商品主图url集合 数组") + private List pictureUrls; + + @ApiModelProperty("批次的商品总数") + private Integer total; + +} diff --git a/src/main/java/com/mixi/model/vo/TProductBatchUploadVo.java b/src/main/java/com/mixi/model/vo/TProductBatchUploadVo.java new file mode 100644 index 0000000..54ee81f --- /dev/null +++ b/src/main/java/com/mixi/model/vo/TProductBatchUploadVo.java @@ -0,0 +1,30 @@ +package com.mixi.model.vo; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; +import java.util.List; + +/** + *

+ * 商品表上传vo + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Getter +@Setter +@ApiModel(value = "TProductBatchUploadVo") +public class TProductBatchUploadVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("上传的商品id数组") + private List productIds; + +} diff --git a/src/main/java/com/mixi/model/vo/TProductSingleUploadVo.java b/src/main/java/com/mixi/model/vo/TProductSingleUploadVo.java new file mode 100644 index 0000000..1901181 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/TProductSingleUploadVo.java @@ -0,0 +1,43 @@ +package com.mixi.model.vo; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.io.Serializable; +import java.util.List; + +/** + *

+ * 商品表上传vo + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ApiModel(value = "TProductSingleUploadVo") +public class TProductSingleUploadVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("上传的商品id") + private String productId; + + @ApiModelProperty("文件主图url") + private String pictureUrl; + + @ApiModelProperty("文件名") + private String pictureName; + + @ApiModelProperty("文件md5值,去重用") + private String md5; + +} diff --git a/src/main/java/com/mixi/model/vo/TProductUploadVo.java b/src/main/java/com/mixi/model/vo/TProductUploadVo.java new file mode 100644 index 0000000..cb40842 --- /dev/null +++ b/src/main/java/com/mixi/model/vo/TProductUploadVo.java @@ -0,0 +1,42 @@ +package com.mixi.model.vo; + + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; + +import javax.validation.constraints.NotEmpty; +import java.io.Serializable; +import java.util.List; + +/** + *

+ * 商品表上传vo + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +@ApiModel(value = "TProductUploadVo") +public class TProductUploadVo implements Serializable { + + private static final long serialVersionUID = 1L; + + @ApiModelProperty("文件主图url") + private String pictureUrl; + + @ApiModelProperty("文件名") + private String pictureName; + + @ApiModelProperty("商品md5值") + private String md5; + +} diff --git a/src/main/java/com/mixi/schedule/ReCollocationSchedule.java b/src/main/java/com/mixi/schedule/ReCollocationSchedule.java new file mode 100644 index 0000000..7d621a1 --- /dev/null +++ b/src/main/java/com/mixi/schedule/ReCollocationSchedule.java @@ -0,0 +1,36 @@ +package com.mixi.schedule; + +import cn.hutool.core.exceptions.ExceptionUtil; +import com.mixi.service.TProductService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +@Slf4j +@Component +public class ReCollocationSchedule { + + @Resource + private TProductService tProductService; + + /** + * 重新搭配(当时条件不够的),每天一点重新计算 + * + * @author yl + * @since 2023-04-13 + */ +// @Scheduled(cron = "0 0 1 * * ?") +// @Scheduled(cron = "0 0/2 * * * ?") + public void websocketHeartBeatTask() { + log.info("定时任务-商品重新搭配开始---------"); + try { + tProductService.reCollocationTask(); + } catch (Exception e) { + log.error("商品重新搭配异常###{}", ExceptionUtil.stacktraceToString(e)); + } + log.info("定时任务-商品重新搭配完成---------"); + } + +} diff --git a/src/main/java/com/mixi/service/AccountService.java b/src/main/java/com/mixi/service/AccountService.java new file mode 100644 index 0000000..b28409d --- /dev/null +++ b/src/main/java/com/mixi/service/AccountService.java @@ -0,0 +1,370 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.mixi.common.config.exception.BusinessException; +import com.mixi.common.context.UserContext; +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.security.jwt.JWTTokenHelper; +import com.mixi.common.utils.*; +import com.mixi.mapper.AccountMapper; +import com.mixi.mapper.entity.*; +import com.mixi.model.dto.*; +import com.mixi.model.vo.*; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.expression.LongValue; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 服务实现类 + * + * @author easy-generator + * @since 2022-07-06 + */ +@Slf4j +@Service +public class AccountService extends ServiceImpl{ + @Resource + private AccountMapper accountMapper; + @Resource + private JWTTokenHelper jwtTokenHelper; + @Resource + private RoleService roleService; + @Resource + private AccountStoreService accountStoreService; + @Resource + private StoreService storeService; + + + public PageBaseResponse queryUserPage(QueryAccountPageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(!org.springframework.util.StringUtils.isEmpty(query.getUserName())){ + queryWrapper.like(TAccount.USER_NAME, query.getUserName()); + } + if(!org.springframework.util.StringUtils.isEmpty(query.getUserPhone())){ + queryWrapper.like(TAccount.USER_PHONE, query.getUserPhone()); + } + if(StringUtils.isNotBlank(query.getRoleId())){ + queryWrapper.eq(TAccount.ROLE_ID,query.getRoleId()); + } + if(Objects.nonNull(query.getState())){ + queryWrapper.eq(TAccount.STATE,query.getState()); + } + if(Objects.nonNull(query.getCreateDateStart())){ + queryWrapper.ge(TAccount.CREATE_DATE, new Date(query.getCreateDateStart())); + } + if(Objects.nonNull(query.getCreateDateEnd())){ + queryWrapper.le(TAccount.CREATE_DATE,new Date(query.getCreateDateEnd())); + } + queryWrapper.orderByDesc(TAccount.ID); + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if(CollectionUtils.isEmpty(page.getRecords())){ + return PageBaseResponse.success(new Page<>()); + } + //角色map + List roleIds = page.getRecords().stream().map(TAccount::getRoleId).collect(Collectors.toList()); + List roleVOS = roleService.queryByRoleIds(roleIds); + Map roleIdToNameMap = CollectionUtil.emptyIfNull(roleVOS).stream().collect(Collectors.toMap(RoleVO::getId,RoleVO::getName)); + //店铺map + List accountIds = page.getRecords().stream().map(TAccount::getId).collect(Collectors.toList()); + List accountStores = accountStoreService.findByAccountIds(accountIds); + Map> accountIdToStoreIdsMap = + CollectionUtil.emptyIfNull(accountStores).stream() + .collect(Collectors.groupingBy(TAccountStore::getAccountId, Collectors.mapping(TAccountStore::getStoreId,Collectors.toList()))); + //店铺ids + List storeIds = CollectionUtil.emptyIfNull(accountStores).stream().map(TAccountStore::getStoreId).collect(Collectors.toList()); + List storeVOS = storeService.queryByStoreIds(storeIds); + Map storeIdToNameMap = CollectionUtil.emptyIfNull(storeVOS).stream().collect(Collectors.toMap(StoreVO::getId,StoreVO::getName)); + + IPage convert = page.convert((Function) + account -> { + AccountVO accountVO = CopyUtil.copyObject(account,AccountVO.class); + accountVO.setRoleName(roleIdToNameMap.get(accountVO.getRoleId().toString())); + accountVO.setCreateDate(account.getCreateDate().getTime()); + accountVO.setStateName(account.getState() == 0 ?"Deactivated" :"Activated"); + accountVO.setAppUserName(account.getAppUser() == 0 ?"No" :"Yes"); + List storeNameList = Lists.newArrayList(); + accountVO.setStoreName(storeNameList); + List storeIdList = accountIdToStoreIdsMap.get(account.getId()); + if(!CollectionUtils.isEmpty(storeIdList)){ + accountVO.setStoreIds(storeIdList.stream().map(v ->v.toString()).collect(Collectors.toList())); + storeIdList.forEach( storeId ->{ + if(storeIdToNameMap.containsKey(storeId.toString())){ + storeNameList.add(storeIdToNameMap.get(storeId.toString())); + } + }); + } + return accountVO; + }); + return PageBaseResponse.success(convert); + } + + @Transactional + public Boolean saveOrEdit(AccountEditDTO accountEditDTO) { + //检验角色和门店 + validateStoreAndRole(accountEditDTO.getStoreIds() + .stream() + .filter(Objects::nonNull).map(Long::valueOf).collect(Collectors.toList()) + ,Long.valueOf(accountEditDTO.getRoleId())); + //校验用户名和账号 + validateSameName(accountEditDTO.getId(),accountEditDTO.getUserName(),accountEditDTO.getUserAccount()); + //校验 + if (StringUtils.isNotBlank(accountEditDTO.getId())) { + TAccount account = accountMapper.selectById(accountEditDTO.getId()); + Assert.notNull(account, "Unknown Account !"); + + TAccount update = CopyUtil.copyObject(accountEditDTO,TAccount.class); + update.setId(account.getId()); + update.setRoleId(Long.valueOf(accountEditDTO.getRoleId())); + update.setUpdateDate(DateUtil.getByTimeZone(accountEditDTO.getTimeZone())); + accountMapper.updateById(update); + //修改关联门店信息 + accountStoreService.updateByAccount(account.getId(), + accountEditDTO.getStoreIds().stream().map(id ->Long.valueOf(id)).collect(Collectors.toList())); + + } else { + TAccount save = CopyUtil.copyObject(accountEditDTO,TAccount.class); + save.setRoleId(Long.valueOf(accountEditDTO.getRoleId())); + save.setCreateDate(DateUtil.getByTimeZone(accountEditDTO.getTimeZone())); + save.setState(1); + accountMapper.insert(save); + //添加关联信息 + accountStoreService.saveByAccount(save.getId(), + accountEditDTO.getStoreIds().stream().map(id ->Long.valueOf(id)).collect(Collectors.toList())); + + } + return Boolean.TRUE; + } + private void validateStoreAndRole(List storeIds,Long roleId){ + Assert.isTrue(roleService.exist(roleId),"The selection role does not exist!"); + List storeVOS = storeService.queryByStoreIds(storeIds); + Assert.isTrue(!CollectionUtils.isEmpty(storeVOS) && storeIds.size() == storeVOS.size() + ,"Select stores that do not match reality!"); + + } + /** + *校验用户名和账户是否重复 + * @param id + * @param userName + * @param userAccount + */ + private void validateSameName(String id ,String userName, String userAccount){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(Objects.nonNull(id)){ + queryWrapper.ne(TAccount.ID,id); + } + queryWrapper.and(wraper -> + wraper.eq(TAccount.USER_NAME, userName) + .or().eq(TAccount.USER_ACCOUNT,userAccount)); + Assert.isTrue(!accountMapper.exists(queryWrapper),"Duplicate user name or account!"); + } + @Transactional + public Boolean delete(StoreDeleteDTO deleteDTO) { + TAccount account = accountMapper.selectById(deleteDTO.getId()); + Assert.notNull(account,"unknown Account!"); + accountMapper.deleteById(deleteDTO.getId()); + //删除关联的门店 + accountStoreService.deleteByAccount(Long.valueOf(deleteDTO.getId())); + return Boolean.TRUE; + } + + @Transactional + public AccountLoginVO login(AccountLoginDTO accountLoginDTO) { + TAccount tAccount = getOneByAcount(accountLoginDTO.getUserAccount()); + Assert.notNull(tAccount,"User not registered!"); + Assert.isTrue(accountLoginDTO.getPassword().equals(tAccount.getUserPassword()), "Password error!"); + Assert.isTrue(tAccount.getState()!= 0, "User deactivated!"); + + AccountLoginVO response = CopyUtil.copyObject(tAccount, AccountLoginVO.class); + String token =LocalCacheUtils.getTokenCache(String.valueOf(tAccount.getId())); + if(StringUtils.isNotBlank(token)){ + //用户已登入 + response.setToken(token); + }else{ + response.setToken(createAccountToken(tAccount.getId(),tAccount.getUserName(),tAccount.getUserAccount())); + } + response.setUserId(tAccount.getId().toString()); + return response; + } + private String createAccountToken(Long userId,String userName,String userAccount){ + AuthPrincipalVo principal = new AuthPrincipalVo(); + principal.setId(userId); + principal.setUsername(userName); + principal.setSource("WEB"); + String token = jwtTokenHelper.createToken(principal); + LocalCacheUtils.setTokenCache(String.valueOf(userId), token); + return token; + } + private String createAppAccountToken(Long userId,String userName,String userAccount){ + AuthPrincipalVo principal = new AuthPrincipalVo(); + principal.setId(userId); + principal.setUsername(userName); + principal.setSource("APP"); + String token = jwtTokenHelper.createToken(principal); + LocalCacheUtils.setTokenCache("APP_"+userId, token); + return token; + } + @Transactional + public AppAccountLoginVO appLogin(AppAccountLoginDTO accountLoginDTO) { + TAccount tAccount = getOneByPhone(accountLoginDTO.getUserPhone()); + Assert.notNull(tAccount,"User not registered!"); + Assert.isTrue(accountLoginDTO.getPassword().equals(tAccount.getUserPassword()), "Password error!"); + + AppAccountLoginVO response = CopyUtil.copyObject(tAccount, AppAccountLoginVO.class); + String token =LocalCacheUtils.getTokenCache("APP_"+tAccount.getId()); + if(StringUtils.isNotBlank(token)){ + //用户已登入 + response.setToken(token); + }else{ + response.setToken(createAppAccountToken(tAccount.getId(),tAccount.getUserName(),tAccount.getUserAccount())); + } + response.setUserId(tAccount.getId().toString()); + //获取门店信息 + response.setStoreList(storeService.queryUserStoreByUserId(tAccount.getId())); + return response; + } + + @Transactional + public Boolean forgetPwd(AccountRegisterDTO accountDTO) { + Assert.isTrue(accountDTO.getPassword().equals(accountDTO.getConfirmPassword()), "Inconsistent password input!"); + TAccount emailAccount = getOneByName(accountDTO.getUserName(),null); + Assert.notNull(emailAccount, "User not registered!"); + updatePwdByName(accountDTO.getPassword(), accountDTO.getUserName()); + return Boolean.TRUE; + } + @Transactional + public Boolean appForgetPwd(AccountRegisterDTO accountDTO) { + Assert.isTrue(accountDTO.getPassword().equals(accountDTO.getConfirmPassword()), "Inconsistent password input!"); + TAccount emailAccount = getOneByName(accountDTO.getUserName(),1); + Assert.notNull(emailAccount, "User not registered!"); + updatePwdByName(accountDTO.getPassword(), accountDTO.getUserName()); + return Boolean.TRUE; + } + @Transactional + public Boolean enableAccount(AccountEnableDTO accountEnableDTO) { + TAccount account = accountMapper.selectById(accountEnableDTO.getId()); + Assert.notNull(account,"unknown Account!"); + Assert.isTrue(!account.getState().equals(accountEnableDTO.getEnable()) + ,"Account "+(account.getState()==1 ?"has been enabled !" :"disabled !" )); + account.setState(accountEnableDTO.getEnable()); + accountMapper.updateById(account); + //登出,删除缓存 + LocalCacheUtils.clearTokenCache(String.valueOf(account.getId())); + return Boolean.TRUE; + } + + private void updatePwdByName(String password, String userName) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_name", userName); + TAccount accountNew = new TAccount(); + accountNew.setUserPassword(password); + accountMapper.update(accountNew, queryWrapper); + } + + private TAccount getOneByName(String name,Integer appUser) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(TAccount.USER_NAME, name); + if(Objects.nonNull(appUser)){ + queryWrapper.eq(TAccount.APP_USER, appUser); + } + return accountMapper.selectOne(queryWrapper); + } + private TAccount getOneByAcount(String account) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(TAccount.USER_ACCOUNT, account); + return accountMapper.selectOne(queryWrapper); + } + private TAccount getOneByPhone(String phone) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(TAccount.USER_PHONE, phone); + queryWrapper.eq(TAccount.APP_USER, 1); + return accountMapper.selectOne(queryWrapper); + } + public Boolean existByRoleId(Long roleId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(TAccount.ROLE_ID,roleId); + return accountMapper.exists(queryWrapper); + } + + public Boolean logout(AccountLogoutDTO accountLogoutDTO) { + //jwt本身失效比较难做 统一用缓存实现 删除缓存就失效 + String token = LocalCacheUtils.getTokenCache(String.valueOf(accountLogoutDTO.getUserId())); + if(StringUtils.isNotBlank(token)){ + LocalCacheUtils.clearTokenCache(String.valueOf(accountLogoutDTO.getUserId())); + } + return Boolean.TRUE; + } + public Boolean appLogout(AccountLogoutDTO accountLogoutDTO) { + //jwt本身失效比较难做 统一用缓存实现 删除缓存就失效 + String token = LocalCacheUtils.getTokenCache("APP_"+accountLogoutDTO.getUserId()); + if(StringUtils.isNotBlank(token)){ + LocalCacheUtils.clearTokenCache("APP_"+accountLogoutDTO.getUserId()); + } + return Boolean.TRUE; + } + + public Boolean isLogin(AccountLogoutDTO accountLogoutDTO) { + String token = LocalCacheUtils.getTokenCache(String.valueOf(accountLogoutDTO.getUserId())); + if(StringUtils.isNotBlank(token)){ + return Boolean.TRUE; + } + return Boolean.FALSE; + } + public Boolean appIsLogin(AccountLogoutDTO accountLogoutDTO) { + String token = LocalCacheUtils.getTokenCache("APP_"+accountLogoutDTO.getUserId()); + if(StringUtils.isNotBlank(token)){ + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + public List findByIds(List ids) { + return accountMapper.selectBatchIds(ids); + } + + /** + * 查询所有用户 + * @return + */ + public List queryAll() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + return accountMapper.selectList(queryWrapper); + } + /** + * 查询当前用户对应门店下所有用户 + * @return + */ + public List queryAllUserInfoByCurrentUser(Long userId){ + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + Long currentUserId = authPrincipalVo.getId(); + if(Objects.nonNull(userId)){ + currentUserId = userId; + } + //查询用户店铺 + List accountStores = accountStoreService.findByAccountIds(Collections.singletonList(currentUserId)); + Assert.notEmpty(accountStores,"unknown Store!"); + List storeIds = accountStores.stream().map(TAccountStore::getStoreId).collect(Collectors.toList()); + //查询当前用户门店的所有用户 + List storeUserInfos = accountStoreService.findByStoreIds(storeIds); + return storeUserInfos; + } + +} diff --git a/src/main/java/com/mixi/service/AccountStoreService.java b/src/main/java/com/mixi/service/AccountStoreService.java new file mode 100644 index 0000000..5f026e4 --- /dev/null +++ b/src/main/java/com/mixi/service/AccountStoreService.java @@ -0,0 +1,72 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.mixi.mapper.TAccountStoreMapper; +import com.mixi.mapper.entity.TAccount; +import com.mixi.mapper.entity.TAccountStore; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.print.DocFlavor; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 服务实现类 + * + * @author easy-generator + * @since 2022-03-07 + */ +@Slf4j +@Service +public class AccountStoreService extends ServiceImpl{ + @Resource + private TAccountStoreMapper tAccountStoreMapper; + + + public List findByAccountIds(List accountIds) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in(TAccountStore.ACCOUNT_ID,accountIds); + return tAccountStoreMapper.selectList(queryWrapper); + } + public List findByStoreIds(List storeIds) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in(TAccountStore.STORE_ID,storeIds); + return tAccountStoreMapper.selectList(queryWrapper); + } + public Boolean existByStoreId(Long storeId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(TAccountStore.STORE_ID,storeId); + return tAccountStoreMapper.exists(queryWrapper); + } + public void updateByAccount(Long accountId,List storeIds) { + //先删后增 + deleteByAccount(accountId); + saveByAccount(accountId,storeIds); + } + public void deleteByAccount(Long accountId) { + QueryWrapper deleteWrapper = new QueryWrapper<>(); + deleteWrapper.eq(TAccountStore.ACCOUNT_ID,accountId); + tAccountStoreMapper.delete(deleteWrapper); + } + public void saveByAccount(Long accountId,List storeIds) { + if(CollectionUtil.isEmpty(storeIds)){ + return; + } + List accountStores = + storeIds.stream().map(storeId ->{ + TAccountStore store = new TAccountStore(); + store.setAccountId(accountId); + store.setStoreId(storeId); + store.setCreateDate(new Date()); + return store; + }).collect(Collectors.toList()); + this.saveBatch(accountStores); + } + +} diff --git a/src/main/java/com/mixi/service/ColorLoopUpTableService.java b/src/main/java/com/mixi/service/ColorLoopUpTableService.java new file mode 100644 index 0000000..e01a617 --- /dev/null +++ b/src/main/java/com/mixi/service/ColorLoopUpTableService.java @@ -0,0 +1,29 @@ +package com.mixi.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mixi.mapper.ColorLoopUpTableMapper; +import com.mixi.mapper.entity.ColorLookupTable; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +@Service +public class ColorLoopUpTableService extends ServiceImpl{ + + @Resource + private ColorLoopUpTableMapper colorLoopUpTableMapper; + + public ColorLookupTable getByColorValue(Integer colorValue) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("color_value", colorValue); + return colorLoopUpTableMapper.selectOne(queryWrapper); + } + + public List getByColorValueList(List colorValues) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("color_value", colorValues); + return colorLoopUpTableMapper.selectList(queryWrapper); + } +} diff --git a/src/main/java/com/mixi/service/LabelService.java b/src/main/java/com/mixi/service/LabelService.java new file mode 100644 index 0000000..7e35033 --- /dev/null +++ b/src/main/java/com/mixi/service/LabelService.java @@ -0,0 +1,190 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.map.MapUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.base.Function; +import com.mixi.common.context.UserContext; +import com.mixi.common.enums.LabelTypeEnum; +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.utils.CopyUtil; +import com.mixi.common.utils.DateUtil; +import com.mixi.mapper.TLablelMapper; +import com.mixi.mapper.entity.TAccount; +import com.mixi.mapper.entity.TAccountStore; +import com.mixi.mapper.entity.TLabel; +import com.mixi.mapper.entity.TRole; +import com.mixi.model.dto.LabelAddOrEditDTO; +import com.mixi.model.dto.QueryLabelPageDTO; +import com.mixi.model.dto.StoreDeleteDTO; +import com.mixi.model.vo.AllRoleVO; +import com.mixi.model.vo.AuthPrincipalVo; +import com.mixi.model.vo.LabelVO; +import com.mixi.model.vo.StoreVO; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 标签服务实现类 + * + * @author easy-generator + * @since 2023-03-06 + */ +@Slf4j +@Service +public class LabelService extends ServiceImpl { + @Resource + private TLablelMapper tLablelMapper; + @Resource + private AccountService accountService; + @Resource + private ProductLabelService productLabelService; + @Resource + private StoreService storeService; + + + public PageBaseResponse queryLabelPage(QueryLabelPageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!org.springframework.util.StringUtils.isEmpty(query.getName())) { + queryWrapper.like(TLabel.NAME, query.getName()); + } + if (!org.springframework.util.StringUtils.isEmpty(query.getType())) { + LabelTypeEnum labelTypeEnum = LabelTypeEnum.of(query.getType()); + Assert.notNull(labelTypeEnum,"unknown Label Type!"); + queryWrapper.eq(TLabel.TYPE, query.getType()); + } + if (Objects.nonNull(query.getCreateDateStart())) { + queryWrapper.ge(TLabel.CREATE_DATE, new Date(query.getCreateDateStart())); + } + if (Objects.nonNull(query.getCreateDateEnd())) { + queryWrapper.le(TLabel.CREATE_DATE, new Date(query.getCreateDateEnd())); + } + queryWrapper.orderByDesc("id"); + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if (CollectionUtils.isEmpty(page.getRecords())) { + return PageBaseResponse.success(new Page<>()); + } + List accountIds = page.getRecords().stream().map(TLabel::getCreateUser).collect(Collectors.toList()); + List accounts = accountService.findByIds(accountIds); + Map idToNameMap = CollectionUtil.isEmpty(accounts) ? MapUtil.empty(): + accounts.stream().collect(Collectors.toMap(TAccount::getId,TAccount::getUserName)); + IPage convert = page.convert((Function) + store -> + { + LabelVO result = CopyUtil.copyObject(store, LabelVO.class); + result.setId(store.getId().toString()); + result.setCreateUserName(idToNameMap.get(store.getCreateUser())); + result.setCreateDate(store.getCreateDate().getTime()); + return result; + }); + return PageBaseResponse.success(convert); + } + @Transactional + public Boolean saveOrEdit(LabelAddOrEditDTO labelAddOrEditDTO) { + LabelTypeEnum labelTypeEnum = LabelTypeEnum.of(labelAddOrEditDTO.getType()); + Assert.notNull(labelTypeEnum,"unknown Label Type!"); + //校验 + if (StringUtils.isNotBlank(labelAddOrEditDTO.getId())) { + TLabel label = tLablelMapper.selectById(labelAddOrEditDTO.getId()); + Assert.notNull(label, "Unknown Label !"); + //去重 + validateSameName(Long.valueOf(labelAddOrEditDTO.getId()),labelAddOrEditDTO.getName(),labelAddOrEditDTO.getType()); + label.setType(labelAddOrEditDTO.getType()); + label.setName(labelAddOrEditDTO.getName()); + label.setRemarks(labelAddOrEditDTO.getRemarks()); + label.setUpdateDate(DateUtil.getByTimeZone(labelAddOrEditDTO.getTimeZone())); + tLablelMapper.updateById(label); + } else { + //去重 + validateSameName(null,labelAddOrEditDTO.getName(),labelAddOrEditDTO.getType()); + TLabel lablel = TLabel.builder() + .type(labelAddOrEditDTO.getType()) + .name(labelAddOrEditDTO.getName()) + .remarks(labelAddOrEditDTO.getRemarks()) + .createUser(UserContext.getUserHolder().getId()) + .createDate(DateUtil.getByTimeZone(labelAddOrEditDTO.getTimeZone())) + .build(); + tLablelMapper.insert(lablel); + } + return Boolean.TRUE; + } + + /** + * + * @param id + * @param name + * @param type + */ + private void validateSameName(Long id ,String name, String type){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(Objects.nonNull(id)){ + queryWrapper.ne(TLabel.ID,id); + } + queryWrapper.eq(TLabel.NAME,name); +// queryWrapper.eq(TLabel.TYPE,type); + Assert.isTrue(!tLablelMapper.exists(queryWrapper),"Duplicate Label name!"); + } + + @Transactional + public Boolean delete(StoreDeleteDTO deleteDTO) { + TLabel label = tLablelMapper.selectById(deleteDTO.getId()); + Assert.notNull(label,"unknown Label!"); + tLablelMapper.deleteById(deleteDTO.getId()); + //todo 删除关联该标签对应的门店标签 + productLabelService.deleteByLabelId(deleteDTO.getId()); + return Boolean.TRUE; + } + + /** + * 查询商品标签列表 + * @return + */ + public List queryProductLabel(){ + //更改成->商品对应用户的门店下所有用户的标签 + QueryWrapper queryWrapper = new QueryWrapper<>(); + List accountStores = accountService.queryAllUserInfoByCurrentUser(null); + queryWrapper.in("create_user",accountStores.stream().map(TAccountStore::getAccountId).collect(Collectors.toList())); + List all = tLablelMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(all) ? null : + CopyUtil.copyList(all, LabelVO.class,(o, d)->{ + d.setId(o.getId().toString()); + }); + } + /** + * 根据ids + * @return + */ + public Map queryMapByIds(List ids){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("id",ids); + List all = tLablelMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(all) ? null :all.stream().collect(Collectors.toMap(TLabel::getId,v->v)); + } + /** + * 查询新品标签 + * @return + */ + public List queryNewProductLabel(){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("type","NEW_PRODUCT"); + List all = tLablelMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(all) ? null :all; + } + +} diff --git a/src/main/java/com/mixi/service/MiTuExportService.java b/src/main/java/com/mixi/service/MiTuExportService.java new file mode 100644 index 0000000..71fc6e9 --- /dev/null +++ b/src/main/java/com/mixi/service/MiTuExportService.java @@ -0,0 +1,25 @@ +package com.mixi.service; + +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.mapper.entity.MiTuExport; +import com.mixi.model.dto.QueryMiTuExportPageDTO; +import org.springframework.core.io.InputStreamResource; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.FileNotFoundException; + +/** + * 店铺服务实现类 + * + * @author easy-generator + * @since 2023-03-06 + */ +public interface MiTuExportService { + + + PageBaseResponse queryMiTuExportPage(QueryMiTuExportPageDTO query); + + void exportMiTuReport(Long id, HttpServletResponse response) throws FileNotFoundException; +} diff --git a/src/main/java/com/mixi/service/PanToneService.java b/src/main/java/com/mixi/service/PanToneService.java new file mode 100644 index 0000000..152409c --- /dev/null +++ b/src/main/java/com/mixi/service/PanToneService.java @@ -0,0 +1,143 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.support.SFunction; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.mixi.common.config.exception.BusinessException; +import com.mixi.common.utils.CopyUtil; +import com.mixi.mapper.PanToneMapper; +import com.mixi.mapper.entity.ColorLookupTable; +import com.mixi.mapper.entity.PanTone; +import com.mixi.model.dto.GetRgbByHsvBatchDTO; +import com.mixi.model.vo.PantoneVO; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + + +@Service +public class PanToneService extends ServiceImpl{ + + @Resource + private PanToneMapper panToneMapper; + @Resource + private ColorLoopUpTableService colorLoopUpTableService; + + public PantoneVO getByHSV(Integer h, Integer s, Integer v) { + int value = (h * 101 *101)+ (s*101) +v; + ColorLookupTable colorLookupTable = colorLoopUpTableService.getByColorValue(value); + if(Objects.isNull(colorLookupTable)){ + return new PantoneVO(); + } + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("pantone_index", colorLookupTable.getColorIndex()); + PanTone panTone = panToneMapper.selectOne(queryWrapper); + if(Objects.isNull(panTone)){ + throw new BusinessException("Pantone value does not exist !"); + } + return coverPanToneToVo(panTone); + } + + public PantoneVO getByTCX(String txc) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("tcx", txc); + List panTones = panToneMapper.selectList(queryWrapper); + if(CollectionUtil.isEmpty(panTones)){ + throw new BusinessException("Pantone value does not exist !"); + } + return coverPanToneToVo(panTones.get(0)); + } + + public PantoneVO getByRGB(Integer r,Integer g,Integer b) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("r", r); + queryWrapper.eq("g", g); + queryWrapper.eq("b", b); + PanTone panTones = panToneMapper.selectOne(queryWrapper); + return coverPanToneToVo(panTones); + } + + public List getRgbByHsvBatch(List hsvBatch) { + if(hsvBatch.size() >15){ + throw new BusinessException("hsv value cannot exceed the maximum of 15"); + } + List colorValues = Lists.newArrayList(); + Map valueToHsv = Maps.newHashMap(); + hsvBatch.forEach( hsv->{ + if (Objects.isNull(hsv)) { + return; + } + Integer h = hsv.getH(); + Integer s = hsv.getS(); + Integer v = hsv.getV(); + int value = (h * 101 *101)+ (s*101) +v; + colorValues.add(value); + valueToHsv.put(value,hsv); + }); + List colorLookupTables = colorLoopUpTableService.getByColorValueList(colorValues); + if(Objects.isNull(colorLookupTables)){ + return Lists.newArrayList(); + } + Map IndexToValue = colorLookupTables.stream() + .collect(Collectors.toMap(v->v.getColorIndex(),v ->v.getColorValue(),(V1,V2) ->V1)); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("pantone_index", colorLookupTables.stream() + .map(ColorLookupTable::getColorIndex).collect(Collectors.toList())); + return coverPanToneToVoList(panToneMapper.selectList(queryWrapper),IndexToValue,valueToHsv,hsvBatch); + } + + private PantoneVO coverPanToneToVo(PanTone panTone){ + if(Objects.isNull(panTone)){ + return null; + } + PantoneVO pantoneVO = CopyUtil.copyObject(panTone,PantoneVO.class); + pantoneVO.setR(panTone.getR()); + pantoneVO.setG(panTone.getG()); + pantoneVO.setB(panTone.getB()); + pantoneVO.setId(panTone.getPantoneIndex()); + return pantoneVO; + } + private List coverPanToneToVoList(List panTones + ,Map indexToValue, Map valueToHsv, + List hsvBatch){ + if(Objects.isNull(panTones)){ + throw new BusinessException("Pantone value does not exist !"); + } + List templateResposne = CopyUtil.copyList(panTones,PantoneVO.class,(o,d)->{ + d.setId(o.getPantoneIndex()); + GetRgbByHsvBatchDTO getRgbByHsvBatchDTO = valueToHsv.get(indexToValue.get(o.getPantoneIndex())); + if(Objects.nonNull(getRgbByHsvBatchDTO)){ + d.setH(getRgbByHsvBatchDTO.getH()); + d.setS(getRgbByHsvBatchDTO.getS()); + d.setV(getRgbByHsvBatchDTO.getV()); + } + }); + Map valueToPantoneVo = templateResposne.stream().collect(Collectors.toMap( + v -> (v.getH() * 101 *101)+ (v.getS()*101) +v.getV(), Function.identity(),(value1,value2)-> value1 + )); + List response = Lists.newArrayList(); + //排序给前端 + hsvBatch.forEach( hsv->{ + if (Objects.isNull(hsv)) { + return; + } + int value = (hsv.getH() * 101 *101)+ (hsv.getS()*101) +hsv.getV(); + PantoneVO pantoneVO = valueToPantoneVo.get(value); + if(Objects.isNull(pantoneVO)){ + response.add(new PantoneVO("None","11-1111")); + }else{ + response.add(pantoneVO); + } + }); + return response; + } + +} diff --git a/src/main/java/com/mixi/service/ProductLabelService.java b/src/main/java/com/mixi/service/ProductLabelService.java new file mode 100644 index 0000000..aa5e5a0 --- /dev/null +++ b/src/main/java/com/mixi/service/ProductLabelService.java @@ -0,0 +1,61 @@ +package com.mixi.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mixi.common.utils.CopyUtil; +import com.mixi.mapper.TProductLabelMapper; +import com.mixi.mapper.entity.TProductLabel; +import com.mixi.mapper.entity.TRole; +import com.mixi.model.vo.AllRoleVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +/** + * 标签商品服务实现类 + * + * @author easy-generator + * @since 2023-03-06 + */ +@Slf4j +@Service +public class ProductLabelService extends ServiceImpl { + @Resource + private TProductLabelMapper tProductLabelMapper; + + public void deleteByLabelId(String labelId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(TProductLabel.LABEL_ID, labelId); + tProductLabelMapper.delete(queryWrapper); + } + + public void deleteByProductId(String productId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(TProductLabel.PRODUCT_ID, productId); + tProductLabelMapper.delete(queryWrapper); + } + + + public List findByLabelIds(List labelIds) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in(TProductLabel.LABEL_ID, labelIds); + List result = tProductLabelMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(result)?null : + result.stream().map(TProductLabel::getProductId).distinct().collect(Collectors.toList()); + } + public Map> findByProductIds(List productIds) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in(TProductLabel.PRODUCT_ID, productIds); + List result = tProductLabelMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(result)?null : + result.stream().collect(Collectors.groupingBy(TProductLabel::getProductId)); + } + + +} diff --git a/src/main/java/com/mixi/service/PythonService.java b/src/main/java/com/mixi/service/PythonService.java new file mode 100644 index 0000000..ee93f58 --- /dev/null +++ b/src/main/java/com/mixi/service/PythonService.java @@ -0,0 +1,499 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.mixi.common.config.FileProperties; +import com.mixi.common.config.exception.BusinessException; +import com.mixi.common.utils.AccessLimitUtils; +import com.mixi.mapper.entity.TProduct; +import com.mixi.model.dto.GenerateCollocationDataBaseDTO; +import com.mixi.model.dto.GenerateCollocationQueryDTO; +import com.mixi.model.dto.GenerateCollocationQueryNewDTO; +import com.mixi.model.vo.AppProductColorExtractVO; +import com.mixi.model.vo.GenerateCollocationOutVO; +import lombok.extern.slf4j.Slf4j; +import okhttp3.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Slf4j +@Service +public class PythonService { + + @Resource + private FileProperties fileProperties; + @Value("${access.python.ip:''}") + private String accessPythonIp; + + /** + * 识别对应的属性标签值 + * + * @param pictureUrls + * @param ids + * @return + */ + public JSONObject attributeRecognition(List pictureUrls,List ids) { + //限流校验 + AccessLimitUtils.validate("attributeRecognition", 20); + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(300, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(300, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + Map> content = Maps.newHashMap(); + //识别图片路径数组 + content.put("upload_img_path", pictureUrls); + //识别图片id数组 + content.put("upload_img_id", ids); + RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(content)); + Request request = new Request.Builder() + .url(accessPythonIp + ":9993/api/attribute") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + String bodyStr = null; + try { + log.info("识别python对应的属性标签值请求入参content###{}", JSON.toJSONString(content)); + response = client.newCall(request).execute(); + bodyStr = response.body().string(); + } catch (IOException ioException) { + log.error("PythonService###attributeRecognition异常##{}", ExceptionUtil.getThrowableList(ioException)); + } + log.info("识别python对应的属性标签值结果###{}",bodyStr.trim()); + //去除限流 + AccessLimitUtils.validateOut("attributeRecognition"); + if (Objects.isNull(response)) { + log.error("PythonService##attributeRecognition异常###{}", "response or body is empty!"); + throw new BusinessException("attribute recognition exception!"); + } + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response)); + Boolean result = jsonObject.getBoolean("successful"); + if (result) { + JSONObject attributeJSONObject = JSON.parseObject(bodyStr.trim()); + return attributeJSONObject; + } + log.info("识别python对应的属性标签值异常###{}", jsonObject); + //生成失败 + throw new BusinessException("Atribute recognition exception!"); + } + + /** + * 商品推荐搭配 + * + * @param query + * @param dataBaseMap + * @return + */ + public List generateCollocation( + List query, Map dataBaseMap) { + //限流校验 + AccessLimitUtils.validate("generateCollocation", 20); + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(300, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(300, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + Map content = Maps.newHashMap(); + //范围,范围越大,速度越慢。现在调试阶段可以设为10,也就是从10套中选最好的5套。 + content.put("max_outfits", 5); + content.put("is_best", Boolean.TRUE); + //输出得分最高的时装的套数(topk < range + content.put("topk", 1); + //需要搭配的衣服,数组 + //去重 + List queryAfter = CollectionUtil.emptyIfNull(query).stream().collect(Collectors.collectingAndThen( + Collectors.toCollection(()->new TreeSet<>(Comparator.comparing(GenerateCollocationQueryDTO::getItem_id))),ArrayList::new)); + content.put("query", queryAfter); + //java数据库中存在的商品 + content.put("database", dataBaseMap); + RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(content)); + Request request = new Request.Builder() + .url(accessPythonIp + ":10201/mixi/api/v1.0/generate") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + String bodyStr = null; + try { + log.info("获取python推荐搭配请求入参content###{}", JSON.toJSONString(content)); + response = client.newCall(request).execute(); + bodyStr = response.body().string(); + } catch (IOException ioException) { + log.error("PythonService##attributeRecognition异常###{}", ExceptionUtil.getThrowableList(ioException)); + } + log.info("识获取python推荐搭配请求结果###{}", bodyStr.trim()); + //去除限流 + AccessLimitUtils.validateOut("generateCollocation"); + if (Objects.isNull(response)) { + log.error("PythonService##generateCollocation异常###{}", "response or body is empty!"); + throw new BusinessException("Generate Collocation exception!"); + } + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response)); + Boolean result = jsonObject.getBoolean("successful"); + if (result) { + List collocationOutList = JSON.parseArray(bodyStr.trim(),GenerateCollocationOutVO.class); + return collocationOutList; + } + log.info("获取python推荐搭配请求异常###{}", jsonObject); + //生成失败 + throw new BusinessException("Generate Collocation exception!"); + } + public List generateCollocationNew( + List query, List dataBaseMap) { + //限流校验 + AccessLimitUtils.validate("generateCollocation", 20); + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(300, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(300, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + Map content = Maps.newHashMap(); + //范围,范围越大,速度越慢。现在调试阶段可以设为10,也就是从10套中选最好的5套。 + content.put("max_outfits", 5); + content.put("is_best", Boolean.TRUE); + //输出得分最高的时装的套数(topk < range + content.put("topk", 1); + //需要搭配的衣服,数组 + //去重 +// List queryAfter = CollectionUtil.emptyIfNull(query).stream().collect(Collectors.collectingAndThen( +// Collectors.toCollection(()->new TreeSet<>(Comparator.comparing(GenerateCollocationQueryDTO::getItem_id))),ArrayList::new)); + content.put("query", query); + //java数据库中存在的商品 + content.put("database", dataBaseMap); + RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(content)); + Request request = new Request.Builder() + .url(accessPythonIp + ":9993/api/outfit_matcheroutfit_matcher") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + String bodyStr = null; + try { + log.info("获取python推荐搭配请求入参content###{}", JSON.toJSONString(content)); + response = client.newCall(request).execute(); + bodyStr = response.body().string(); + } catch (IOException ioException) { + log.error("PythonService##attributeRecognition异常###{}", ExceptionUtil.getThrowableList(ioException)); + } + log.info("识获取python推荐搭配请求结果###{}", bodyStr.trim()); + //去除限流 + AccessLimitUtils.validateOut("generateCollocation"); + if (Objects.isNull(response)) { + log.error("PythonService##generateCollocation异常###{}", "response or body is empty!"); + throw new BusinessException("Generate Collocation exception!"); + } + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response)); + Boolean result = jsonObject.getBoolean("successful"); + + if (result) { + System.out.println(bodyStr.trim()); +// JSONObject jsonObject1 = JSONObject.parseObject(bodyStr.trim()); + List collocationOutList = processJson(bodyStr.trim()); + return collocationOutList; + } + log.info("获取python推荐搭配请求异常###{}", jsonObject); + //生成失败 + throw new BusinessException("Generate Collocation exception!"); + } + + public static List processJson(String json) { + List resultList = new ArrayList<>(); + + JSONObject jsonObject = JSON.parseObject(json); + if (jsonObject.containsKey("data")) { + JSONArray dataArray = jsonObject.getJSONArray("data"); + for (int i = 0; i < dataArray.size(); i++) { + JSONObject dataObject = dataArray.getJSONObject(i); + if (dataObject.containsKey("outfits") && dataObject.containsKey("scores")) { + JSONArray outfitsArray = dataObject.getJSONArray("outfits"); + JSONArray scoresArray = dataObject.getJSONArray("scores"); + + List> outfitsList = new ArrayList<>(); + for (int j = 0; j < outfitsArray.size(); j++) { + JSONArray innerArray = outfitsArray.getJSONArray(j); + List innerList = new ArrayList<>(); + for (int k = 0; k < innerArray.size(); k++) { + JSONObject itemObject = innerArray.getJSONObject(k); + GenerateCollocationQueryNewDTO item = new GenerateCollocationQueryNewDTO(); + item.setItem_name(itemObject.getString("item_name")); + item.setSemantic_category(itemObject.getString("semantic_category")); + item.setImage_path(itemObject.getString("image_path")); + innerList.add(item); + } + outfitsList.add(innerList); + } + + List scoresList = new ArrayList<>(); + for (int j = 0; j < scoresArray.size(); j++) { + scoresList.add(scoresArray.getDouble(j)); + } + + GenerateCollocationOutVO vo = new GenerateCollocationOutVO(); + vo.setOutfits(outfitsList); + vo.setScores(scoresList); + + resultList.add(vo); + } + } + } + + return resultList; + } + + /** + * 颜色或者相似度搭配,或者主色提取(同一个接口) + * + * @param query + * @param dataBaseMap + * @return + */ + public Map> similarityRecognition(String mode, List query + , Map dataBaseMap,List productRgbList) { + //限流校验 + AccessLimitUtils.validate("similarityRecognition", 20); + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(300, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(300, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + Map content = Maps.newHashMap(); + //color_feature和hash_feature。分别表示进行颜色匹配和相似度匹配。 + content.put("mode", mode); + //颜色识别 + if("color_feature".equals(mode)){ + List> rgbList = productRgbList.stream() + .map(rgb-> Arrays.asList(Integer.valueOf(rgb.getR()), + Integer.valueOf(rgb.getG()),Integer.valueOf(rgb.getB()))).collect(Collectors.toList()); + List>>> rgbArgList = Lists.newArrayList(); + Map>> map = Maps.newHashMap(); + map.put("RGB",rgbList); + rgbArgList.add(map); + //相似度识别 + content.put("query", rgbArgList); + }else{ + //去重需要搭配的衣服,数组 + List queryAfter = CollectionUtil.emptyIfNull(query).stream().collect(Collectors.collectingAndThen( + Collectors.toCollection(()->new TreeSet<>(Comparator.comparing(GenerateCollocationQueryDTO::getItem_id))),ArrayList::new)); + content.put("query", queryAfter); + } + //输出匹配得分最高的图片(topk < database),暂定5 + content.put("topk", 5); + + //java数据库中存在的商品 + content.put("database", dataBaseMap); + RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(content)); + Request request = new Request.Builder() + .url(accessPythonIp + ":10202/mixi/api/v1.0/retrieval") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + String bodyStr = null; + try { + log.info("获取python颜色或者相似度搭配请求入参content###{}", JSON.toJSONString(content)); + response = client.newCall(request).execute(); + bodyStr = response.body().string(); + } catch (IOException ioException) { + log.error("PythonService##similarityRecognition异常###{}", ExceptionUtil.getThrowableList(ioException)); + } + log.info("识获取python颜色或者相似度搭配请求结果###{}", bodyStr.trim()); + //去除限流 + AccessLimitUtils.validateOut("similarityRecognition"); + if (Objects.isNull(response)) { + log.error("PythonService##similarityRecognition异常###{}", "response or body is empty!"); + throw new BusinessException("Generate Collocation exception!"); + } + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response)); + Boolean result = jsonObject.getBoolean("successful"); + if (result) { + JSONArray jsonArray = JSON.parseArray(bodyStr.trim()); + return resolveMap(jsonArray,mode); + } + log.info("获取python颜色或者相似度搭配请求异常###{}", jsonObject); + //生成失败 + throw new BusinessException("Similarity Recognition Exception!"); + } + private static Map> resolveMap(JSONArray jsonArray,String mode ){ + Map> returnMap = Maps.newHashMap(); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + String queryId ="RGB"; + if("hash_feature".equals(mode)){ + queryId = jsonObject.getJSONObject("query").getString("item_id"); + } + String retrievalJSONString = jsonObject.getJSONObject("retrieval").toJSONString(); + Map> resultValue = JSON.parseObject(retrievalJSONString,Map.class); + List collationProductIdList = Lists.newArrayList(resultValue.keySet()); + returnMap.put(queryId,collationProductIdList); + } + return returnMap; + } + /** + * 主色提取(同一个接口) + * + * @param mode + * @param path + * @param isHsv 1返回hsv值 0返回rgb值 + * @return + */ + public List> colorExtract(String mode,String path,Integer isHsv) { + //限流校验 + AccessLimitUtils.validate("colorExtract", 20); + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(300, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(300, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + Map content = Maps.newHashMap(); + //color_feature和hash_feature。分别表示进行颜色匹配和相似度匹配。 + content.put("mode", mode); + //表示提取主色的数量(最小2,最大10)暂定5 + content.put("color_num", 5); + content.put("return_hsv", isHsv); + //衣服的绝对路径或url(http开头) + content.put("path",path); + RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(content)); + Request request = new Request.Builder() + .url(accessPythonIp + ":10202/mixi/api/v1.0/retrieval") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + String bodyStr = null; + try { + log.info("获取python主色提取请求入参content###{}", JSON.toJSONString(content)); + response = client.newCall(request).execute(); + bodyStr = response.body().string(); + } catch (IOException ioException) { + log.error("PythonService##colorExtract异常###{}", ExceptionUtil.getThrowableList(ioException)); + } + log.info("识获取python主色提取请求结果###{}", bodyStr.trim()); + //去除限流 + AccessLimitUtils.validateOut("colorExtract"); + if (Objects.isNull(response)) { + log.error("PythonService##colorExtract异常###{}", "response or body is empty!"); + throw new BusinessException("Color Extract exception!"); + } + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response)); + Boolean result = jsonObject.getBoolean("successful"); + if (result) { + JSONArray jsonArray = JSON.parseArray(bodyStr.trim()); + return resolveColorExtractList(jsonArray); + } + log.info("获取python主色提取请求异常###{}", jsonObject); + //生成失败 + throw new BusinessException("Color Extract Exception!"); + } + private static List > resolveColorExtractList(JSONArray jsonArray ){ + List> returnList = Lists.newArrayList(); + List innerList= Lists.newArrayList(); + for (int i = 0; i < jsonArray.size(); i++) { + String rgb = jsonArray.getString(i); + innerList.add(rgb); + } + returnList.add(innerList); + return returnList; + } + /** + * + * rgb转hsv + * + * @param r + * @param g + * @param b + * @return + */ + public List rgb2hsv(Integer r ,Integer g,Integer b) { + //限流校验 + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(300, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(300, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + Map content = Maps.newHashMap(); + //color_feature和hash_feature。分别表示进行颜色匹配和相似度匹配。 + content.put("mode", "rgb2hsv"); + //表示提取主色的数量(最小2,最大10)暂定5 + content.put("rgb", Arrays.asList(r,g,b)); + RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(content)); + Request request = new Request.Builder() + .url(accessPythonIp + ":10202/mixi/api/v1.0/retrieval") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + String bodyStr = null; + try { + log.info("获取python rgb转hsv请求入参content###{}", JSON.toJSONString(content)); + response = client.newCall(request).execute(); + bodyStr = response.body().string(); + } catch (IOException ioException) { + log.error("PythonService##rgb2hsv###{}", ExceptionUtil.getThrowableList(ioException)); + } + log.info("识获取python主色 rgb转hsv请求结果###{}", bodyStr.trim()); + if (Objects.isNull(response)) { + log.error("PythonService##rgb2hsv异常###{}", "response or body is empty!"); + throw new BusinessException("rgb2hsv exception!"); + } + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response)); + Boolean result = jsonObject.getBoolean("successful"); + if (result) { + List hsvList = JSON.parseArray(bodyStr.trim(),Integer.class); + return hsvList; + } + log.info("获取python rgb转hsv请求异常###{}", jsonObject); + //生成失败 + throw new BusinessException("rgb2hsv Exception!"); + } + + public static void main(String[] args) { +// String res = "{\"1\":{\"Item\":\"top\",\"Top_length\":[\"Regular\"],\"Top_type\":[\"Sweater\"]},\"2\":{\"Item\":\"top\",\"Top_length\":[\"Regular\"],\"Top_type\":[\"Sweater\"]}}"; +// Map> resultValue = JSON.parseObject(res,Map.class); +// System.out.println(resultValue); + +// String bodyStr = "{\n" + +// " \"mode\": \"color_extract\",\n" + +// " \"color_num\": 5,\n" + +// " \"path\": \"http://18.167.251.121:5568/download/202303/userFile/product/3/61b20df8-dabe-4eca-90a1-8dc804b1eddbrendering_113581965_source_99619122.jpg\"\n" + +// "}"; +// +// List collocationOutList = JSON.parseArray(bodyStr.trim(),GenerateCollocationOutVO.class); +// System.out.println(collocationOutList); +// +// JSONArray jsonArray = JSON.parseArray(bodyStr.trim()); +// System.out.println(resolveColorExtractList(jsonArray)); + + + } + +} diff --git a/src/main/java/com/mixi/service/RoleService.java b/src/main/java/com/mixi/service/RoleService.java new file mode 100644 index 0000000..ca7ef72 --- /dev/null +++ b/src/main/java/com/mixi/service/RoleService.java @@ -0,0 +1,173 @@ +package com.mixi.service; + +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.base.Function; +import com.mixi.common.context.UserContext; +import com.mixi.common.enums.RolePermissionResourceEnum; +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.utils.CopyUtil; +import com.mixi.common.utils.DateUtil; +import com.mixi.mapper.TRoleMapper; +import com.mixi.mapper.entity.TAccount; +import com.mixi.mapper.entity.TRole; +import com.mixi.mapper.entity.TStore; +import com.mixi.model.dto.QueryStorePageDTO; +import com.mixi.model.dto.RoleAddOrEditDTO; +import com.mixi.model.dto.StoreDeleteDTO; +import com.mixi.model.vo.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +/** + * 标签商品服务实现类 + * + * @author easy-generator + * @since 2023-03-07 + */ +@Slf4j +@Service +public class RoleService extends ServiceImpl { + @Resource + private TRoleMapper tRoleMapper; + @Resource + private AccountService accountService; + + public PageBaseResponse queryRolePage(QueryStorePageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!org.springframework.util.StringUtils.isEmpty(query.getName())) { + queryWrapper.like("name", query.getName()); + } + + queryWrapper.orderByDesc("id"); + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if (CollectionUtils.isEmpty(page.getRecords())) { + return PageBaseResponse.success(new Page<>()); + } + IPage convert = page.convert((Function) + role -> + { + RoleVO result = CopyUtil.copyObject(role, RoleVO.class); + result.setId(role.getId().toString()); + result.setRolePermission(JSON.parseObject(role.getResourceInfo(), RolePermissionVO.class)); + return result; + }); + return PageBaseResponse.success(convert); + } + + /** + * 查询权限模板 + * @return + */ + public List queryPermissionListTemplate(){ + return RolePermissionResourceEnum.ofAll(); + } + + /** + * 根据主键查询权限详情 + * @param roleId + * @return + */ + public Boolean exist(Long roleId){ + QueryWrapper roleQueryWrapper = new QueryWrapper<>(); + roleQueryWrapper.eq(TRole.ID,roleId); + return tRoleMapper.exists(roleQueryWrapper); + } + + /** + *校验角色名是否重复 + * @param id + * @param roleName + */ + private void validateSameName(String id ,String roleName){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(Objects.nonNull(id)){ + queryWrapper.ne(TRole.ID,id); + } + queryWrapper.and(wraper -> wraper.eq(TRole.NAME, roleName)); + Assert.isTrue(!tRoleMapper.exists(queryWrapper),"Duplicate role name !"); + } + + /** + * 根据主键批量查询 + * @param roleIds + * @return + */ + public List queryByRoleIds(List roleIds){ + List roles = tRoleMapper.selectBatchIds(roleIds); + return CollectionUtils.isEmpty(roles) ? null : + CopyUtil.copyList(roles, RoleVO.class,(o,d)->{ + d.setId(o.getId().toString()); + }); + } + @Transactional + public Boolean saveOrEdit(RoleAddOrEditDTO roleAddOrEditDTO) { + //校验 + validateSameName(roleAddOrEditDTO.getId(),roleAddOrEditDTO.getName()); + if (StringUtils.isNotBlank(roleAddOrEditDTO.getId())) { + TRole role = tRoleMapper.selectById(roleAddOrEditDTO.getId()); + Assert.notNull(role, "Unknown Role !"); + + role.setName(roleAddOrEditDTO.getName()); + role.setResourceInfo(JSON.toJSONString(roleAddOrEditDTO.getRolePermission())); + role.setUpdateDate(DateUtil.getByTimeZone(roleAddOrEditDTO.getTimeZone())); + tRoleMapper.updateById(role); + } else { + TRole role = TRole.builder() + .name(roleAddOrEditDTO.getName()) + .resourceInfo(JSON.toJSONString(roleAddOrEditDTO.getRolePermission())) + .createDate(DateUtil.getByTimeZone(roleAddOrEditDTO.getTimeZone())) + .build(); + tRoleMapper.insert(role); + } + return Boolean.TRUE; + } + @Transactional + public Boolean delete(StoreDeleteDTO deleteDTO) { + TRole role = tRoleMapper.selectById(deleteDTO.getId()); + Assert.notNull(role, "unknown Role!"); + //todo 存在角色用户关系的不能删除 + Assert.isTrue(!accountService.existByRoleId(role.getId()),"The user has associated the role!"); + tRoleMapper.deleteById(deleteDTO.getId()); + return Boolean.TRUE; + } + + /** + * 查询所有角色 + * @return + */ + public List queryAll(){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + List all = tRoleMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(all) ? null : + CopyUtil.copyList(all, AllRoleVO.class,(o,d)->{ + d.setId(o.getId().toString()); + }); + } + + public RoleVO queryUsrPermission() { + Long accountId = UserContext.getUserHolder().getId(); + TAccount account = accountService.getById(accountId); + Assert.notNull(account, "Unknown User!"); + TRole role = this.getById(account.getRoleId()); + Assert.notNull(role, "Unknown User Role!"); + RoleVO roleVO = CopyUtil.copyObject(role,RoleVO.class); + roleVO.setRolePermission(JSON.parseObject(role.getResourceInfo(), RolePermissionVO.class)); + return roleVO; + } + +} diff --git a/src/main/java/com/mixi/service/StoreService.java b/src/main/java/com/mixi/service/StoreService.java new file mode 100644 index 0000000..9d64e2f --- /dev/null +++ b/src/main/java/com/mixi/service/StoreService.java @@ -0,0 +1,199 @@ +package com.mixi.service; + +import ch.qos.logback.classic.db.names.SimpleDBNameResolver; +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.base.Function; +import com.mixi.common.config.exception.BusinessException; +import com.mixi.common.context.UserContext; +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.security.jwt.JWTTokenHelper; +import com.mixi.common.utils.CopyUtil; +import com.mixi.common.utils.DateUtil; +import com.mixi.common.utils.LocalCacheUtils; +import com.mixi.common.utils.ObjectUtils; +import com.mixi.mapper.AccountMapper; +import com.mixi.mapper.TStoreMapper; +import com.mixi.mapper.entity.*; +import com.mixi.model.dto.*; +import com.mixi.model.vo.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.units.qual.C; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 店铺服务实现类 + * + * @author easy-generator + * @since 2023-03-06 + */ +@Slf4j +@Service +public class StoreService extends ServiceImpl{ + @Resource + private TStoreMapper tStoreMapper; + @Resource + private AccountStoreService accountStoreService; + + public PageBaseResponse queryStorePage(QueryStorePageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(!org.springframework.util.StringUtils.isEmpty(query.getName())){ + queryWrapper.and(wraper -> + wraper.like("name", query.getName()) + .or().like("id", query.getName()) ); + } + queryWrapper.orderByDesc("id"); + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if(CollectionUtils.isEmpty(page.getRecords())){ + return PageBaseResponse.success(new Page<>()); + } + IPage convert = page.convert((Function) + store -> + {StoreVO result = CopyUtil.copyObject(store,StoreVO.class); + result.setId(store.getId().toString()); + result.setCreateDate(store.getCreateDate().getTime()); + return result; + }); + return PageBaseResponse.success(convert); + } + /** + *校验门店是否重复 + * @param id + * @param storeName + */ + private void validateSameName(String id ,String storeName){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + if(Objects.nonNull(id)){ + queryWrapper.ne(TRole.ID,id); + } + queryWrapper.and(wraper -> wraper.eq("name", storeName)); + Assert.isTrue(!tStoreMapper.exists(queryWrapper),"Duplicate store name !"); + } + @Transactional + public Boolean saveOrEdit(StoreAddOrEditDTO storeAddOrEditDTO) { + //校验 + validateSameName(storeAddOrEditDTO.getId(),storeAddOrEditDTO.getName()); + if(StringUtils.isNotBlank(storeAddOrEditDTO.getId())){ + TStore store = tStoreMapper.selectById(storeAddOrEditDTO.getId()); + Assert.notNull(store,"Unknown User Store"); + + store.setAddress(storeAddOrEditDTO.getAddress()); + store.setName(storeAddOrEditDTO.getName()); + store.setRemarks(storeAddOrEditDTO.getRemarks()); + store.setUpdateDate(DateUtil.getByTimeZone(storeAddOrEditDTO.getTimeZone())); + tStoreMapper.updateById(store); + }else { + TStore store = TStore.builder() + .address(storeAddOrEditDTO.getAddress()) + .name(storeAddOrEditDTO.getName()) + .remarks(storeAddOrEditDTO.getRemarks()) + .createDate(DateUtil.getByTimeZone(storeAddOrEditDTO.getTimeZone())) + .build(); + tStoreMapper.insert(store); + } + return Boolean.TRUE; + } + @Transactional + public Boolean delete(StoreDeleteDTO storeDeleteDTO) { + TStore store = tStoreMapper.selectById(storeDeleteDTO.getId()); + Assert.notNull(store,"unknown Store!"); + //todo 关联到了用户的门店不能删除 + Assert.isTrue(!accountStoreService.existByStoreId(store.getId()),"The user has associated the store!"); + tStoreMapper.deleteById(storeDeleteDTO.getId()); + return Boolean.TRUE; + } + + /** + * 根据主键批量查询 + * @param storeIds + * @return + */ + public List queryByStoreIds(List storeIds){ + List stores = tStoreMapper.selectBatchIds(storeIds); + return CollectionUtils.isEmpty(stores) ? null : + CopyUtil.copyList(stores, StoreVO.class,(o,d)->{ + d.setId(o.getId().toString()); + }); + } + + /** + * 查询所有店铺 + * @return + */ + public List queryAll(){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + List all = tStoreMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(all) ? null : + CopyUtil.copyList(all, StoreVO.class,(o,d)->{ + d.setId(o.getId().toString()); + }); + } + + /** + * 查询商品门店列表 + * @return + */ + public List queryUserStore(String storeId,Long userId){ + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + Long currentUserId = authPrincipalVo.getId(); + if(Objects.nonNull(userId)){ + currentUserId = userId; + } + //查询用户店铺 + List accountStores = accountStoreService.findByAccountIds(Collections.singletonList(currentUserId)); + Assert.notEmpty(accountStores,"unknown Store!"); + List storeIds = accountStores.stream().map(TAccountStore::getStoreId).collect(Collectors.toList()); + if (StringUtils.isNotBlank(storeId)){ + storeIds = Collections.singletonList(Long.valueOf(storeId)); + } + //查询当前用户门店 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in(TStore.ID,storeIds); + List all = tStoreMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(all) ? null : + CopyUtil.copyList(all, StoreVO.class,(o, d)->{ + d.setId(o.getId().toString()); + }); + } + + /** + * 查询商品门店列表 + * @return + */ + public List queryUserStoreByUserId(Long userId){ + //查询用户店铺 + List accountStores = accountStoreService.findByAccountIds(Collections.singletonList(userId)); + Assert.notEmpty(accountStores,"unknown Store!"); + List storeIds = accountStores.stream().map(TAccountStore::getStoreId).collect(Collectors.toList()); + //查询当前用户门店 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in(TStore.ID,storeIds); + List all = tStoreMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(all) ? null : + CopyUtil.copyList(all, StoreVO.class,(o, d)->{ + d.setId(o.getId().toString()); + }); + } + /** + * 查询所有店铺总数 + * @return + */ + public Long total(){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + return tStoreMapper.selectCount(queryWrapper); + } + +} diff --git a/src/main/java/com/mixi/service/TAppProductService.java b/src/main/java/com/mixi/service/TAppProductService.java new file mode 100644 index 0000000..41894a4 --- /dev/null +++ b/src/main/java/com/mixi/service/TAppProductService.java @@ -0,0 +1,476 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.mixi.common.config.FileProperties; +import com.mixi.common.context.UserContext; +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.utils.CopyUtil; +import com.mixi.common.utils.DateUtil; +import com.mixi.common.utils.FileUtil; +import com.mixi.common.utils.LocalCacheUtils; +import com.mixi.mapper.TProductMapper; +import com.mixi.mapper.entity.*; +import com.mixi.model.dto.*; +import com.mixi.model.vo.*; +import io.netty.util.internal.StringUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.File; +import java.math.BigDecimal; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +/** + *

+ * 商品表 服务类 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Slf4j +@Service +public class TAppProductService extends ServiceImpl { + + @Resource + private ProductLabelService productLabelService; + @Resource + private LabelService labelService; + @Resource + private TProductStockService tProductStockService; + @Resource + private TProductMapper tProductMapper; + @Resource + private TCustomBuriedPointRecordService tCustomBuriedPointRecordService; + @Resource + private TProductAttributeService tProductAttributeService; + @Resource + private PythonService pythonService ; + @Resource + private StoreService storeService; + @Resource + private FileProperties fileProperties; + @Resource + private PanToneService panToneService; + + + /** + * app分页查询新品列表 + * + * @param query + * @returnN + */ + public PageBaseResponse queryAppNewProductPage(QueryNewProductPageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!StringUtils.isEmpty(query.getStoreId())) { + List productIds= tProductStockService.findByStoreIds(Collections.singletonList(query.getStoreId())); + if(CollectionUtils.isEmpty(productIds)){ + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIds); + } + if (!org.springframework.util.StringUtils.isEmpty(query.getLabelItem())) { + List productIds = tProductAttributeService.findByItemAndType(query.getLabelItem(),null); + if (CollectionUtils.isEmpty(productIds)) { + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIds); + } + //新品商品筛选 + List labels = labelService.queryNewProductLabel(); + if(CollectionUtils.isEmpty(labels)){ + return PageBaseResponse.success(new Page<>()); + } + List selectLabelIds = labels.stream().map(v->v.getId().toString()).collect(Collectors.toList()); + List selectProductIds = productLabelService.findByLabelIds(selectLabelIds); + if(CollectionUtils.isEmpty(selectProductIds)){ + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", selectProductIds); + + //上架 + queryWrapper.eq("on_sale_state", 1); + queryWrapper.eq("upload_state", 1); +// queryWrapper.eq("account_id", UserContext.getUserHolder().getId()); + queryWrapper.orderByDesc("id"); + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if (CollectionUtils.isEmpty(page.getRecords())) { + return PageBaseResponse.success(new Page<>()); + } + List productIds = page.getRecords().stream().map(TProduct::getId).collect(Collectors.toList()); + Map> productToLabelMap = productLabelService.findByProductIds(productIds); + List labelIds = productToLabelMap.values() + .stream() + .map(list->list.stream().map(TProductLabel::getLabelId).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + //标签map + Map labelMap = labelService.queryMapByIds(labelIds); + IPage convert = page.convert((Function) + product -> + { + AppNewProductVO result = CopyUtil.copyObject(product, AppNewProductVO.class); + result.setId(product.getId().toString()); + result.setProductLabelInfo(CopyUtil.copyList(productToLabelMap.get(product.getId()),ProductLabelVO.class,(o,d) ->{ + d.setId(o.getLabelId().toString()); + d.setName(labelMap.get(o.getLabelId()).getName()); + d.setType(labelMap.get(o.getLabelId()).getType()); + })); + return result; + }); + return PageBaseResponse.success(convert); + } + + /** + * app分页查询推荐列表 + * + * @param query + * @returnN + */ + public PageBaseResponse queryRecommendPage(QueryRecommendPageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!org.springframework.util.StringUtils.isEmpty(query.getLabelItem())) { + List productIds = tProductAttributeService.findByItemAndType(query.getLabelItem(),null); + if (CollectionUtils.isEmpty(productIds)) { + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIds); + } + //个性化商品筛选 + List customBuriedPointRecords = tCustomBuriedPointRecordService.getRecommendProduct("BROWSE"); + if(CollectionUtils.isEmpty(customBuriedPointRecords)){ + return PageBaseResponse.success(new Page<>()); + } + List selectProductIds = customBuriedPointRecords.stream().map(v->v.getProductId().toString()).collect(Collectors.toList()); + queryWrapper.in("id", selectProductIds); + + //上架 + queryWrapper.eq("on_sale_state", 1); + queryWrapper.eq("upload_state", 1); +// queryWrapper.eq("account_id", UserContext.getUserHolder().getId()); + queryWrapper.orderByDesc("id"); + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if (CollectionUtils.isEmpty(page.getRecords())) { + return PageBaseResponse.success(new Page<>()); + } + List productIds = page.getRecords().stream().map(TProduct::getId).collect(Collectors.toList()); + Map> productToLabelMap = productLabelService.findByProductIds(productIds); + List labelIds = productToLabelMap.values() + .stream() + .map(list->list.stream().map(TProductLabel::getLabelId).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + //标签map + Map labelMap = labelService.queryMapByIds(labelIds); + IPage convert = page.convert((Function) + product -> + { + AppNewProductVO result = CopyUtil.copyObject(product, AppNewProductVO.class); + result.setId(product.getId().toString()); + result.setProductLabelInfo(CopyUtil.copyList(productToLabelMap.get(product.getId()),ProductLabelVO.class,(o,d) ->{ + d.setId(o.getLabelId().toString()); + d.setName(labelMap.get(o.getLabelId()).getName()); + d.setType(labelMap.get(o.getLabelId()).getType()); + })); + return result; + }); + return PageBaseResponse.success(convert); + } + /** + * app分页查询新品列表 + * + * @param query + * @returnN + */ + public List queryProductSaleRank(QueryProductRankDTO query) { + //商品排行 + List appProductSaleRankVOS = tCustomBuriedPointRecordService.queryProductSaleRank(query); + if(CollectionUtils.isEmpty(appProductSaleRankVOS)){ + return Lists.newArrayList(); + } + List selectProductIds = appProductSaleRankVOS.stream().map(v->Long.valueOf(v.getId())).collect(Collectors.toList()); + + List tProducts = tProductMapper.selectBatchIds(selectProductIds); + if(CollectionUtil.isEmpty(tProducts)){ + //埋点的商品可能被删除 + return Lists.newArrayList(); + } + Map productIdToUrlMap = + CollectionUtil.emptyIfNull(tProducts).stream().collect(Collectors.toMap(TProduct::getId,TProduct::getPictureUrl)); + + Map productIdToObject = + CollectionUtil.emptyIfNull(tProducts).stream().collect(Collectors.toMap(TProduct::getId,Function.identity())); + + Map> productToLabelMap = productLabelService.findByProductIds(selectProductIds); + List labelIds = productToLabelMap.values() + .stream() + .map(list->list.stream().map(TProductLabel::getLabelId).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + //标签map + Map labelMap = labelService.queryMapByIds(labelIds); + //过滤埋点的商品可能被删除 + appProductSaleRankVOS = appProductSaleRankVOS.stream().filter(rank->productIdToUrlMap.containsKey(Long.valueOf(rank.getId()))).collect(Collectors.toList()); + appProductSaleRankVOS.forEach(rank ->{ + rank.setPictureUrl(productIdToUrlMap.get(Long.valueOf(rank.getId()))); + rank.setProductLabelInfo(CopyUtil.copyList(productToLabelMap.get(Long.valueOf(rank.getId())),ProductLabelVO.class,(o,d) ->{ + d.setId(o.getLabelId().toString()); + d.setName(labelMap.get(o.getLabelId()).getName()); + d.setType(labelMap.get(o.getLabelId()).getType()); + })); + TProduct product = productIdToObject.get(Long.valueOf(rank.getId())); + if(Objects.nonNull(product)){ + rank.setColor(product.getColor()); + rank.setRgb(product.getRgb()); + rank.setPrice(product.getPrice()); + } + }); + return appProductSaleRankVOS; + } + /** + * 商品相似度搭配 + * + * @param query + * @returnN + */ + public List productSimilarityMatch(ProductSimilaDTO query) { + //获取该用户所有店铺下所有商品 + //查询用户店铺 + List storeVOS = storeService.queryUserStore(null,null); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + List dataBase = CollectionUtil.isEmpty(productIds)? Lists.newArrayList() : tProductMapper.selectBatchIds(productIds); + if(CollectionUtils.isEmpty(dataBase) || dataBase.size() <= 5){ + //商品数不够 不支持相似度搭配 + return Lists.newArrayList(); + } + + Map tProductIdToAttributeItemNewMap = CollectionUtil.isEmpty(dataBase) ? Maps.newHashMap() + : tProductAttributeService.findByProductAttributesItem(dataBase.stream().map(TProduct::getId).collect(Collectors.toList())); + + Map dataBaseMap = dataBase.stream().collect(Collectors.toMap(p -> p.getId().toString(), + p2 -> GenerateCollocationDataBaseDTO + .builder() + .category(tProductIdToAttributeItemNewMap.get(p2.getId())) + .path(p2.getPictureUrl()).build(),(v1,v2)->v2)); + //商品排行 + Map> similarityRecognitionMap = pythonService.similarityRecognition( + "hash_feature", + Collections.singletonList(GenerateCollocationQueryDTO.builder() + //写死,python只根据本地图片url来识别 + .item_category("top") + .path(query.getPictureUrl()) + //商品id写死,python不需要 java只做映射用 + .item_id("666666").build()),dataBaseMap,null); + if(CollectionUtils.isEmpty(similarityRecognitionMap)){ + return Lists.newArrayList(); + } + List selectProductIds = similarityRecognitionMap.get("666666").stream().map(v->Long.valueOf(v)).collect(Collectors.toList()); + + List tProducts = tProductMapper.selectBatchIds(selectProductIds); + Map productIdToUrlMap = + CollectionUtil.emptyIfNull(tProducts).stream().collect(Collectors.toMap(TProduct::getId,TProduct::getPictureUrl)); + + Map> productToLabelMap = productLabelService.findByProductIds(selectProductIds); + List labelIds = productToLabelMap.values() + .stream() + .map(list->list.stream().map(TProductLabel::getLabelId).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + //标签map + Map labelMap = labelService.queryMapByIds(labelIds); + return CopyUtil.copyList(tProducts,AppNewProductVO.class,(oo,dd)->{ + dd.setId(oo.getId().toString()); + dd.setPictureUrl(productIdToUrlMap.get(oo.getId())); + dd.setProductLabelInfo(CopyUtil.copyList(productToLabelMap.get(oo.getId()),ProductLabelVO.class,(o,d) ->{ + d.setId(o.getLabelId().toString()); + d.setName(labelMap.get(o.getLabelId()).getName()); + d.setType(labelMap.get(o.getLabelId()).getType()); + })); + }); + } + + /** + * 商品颜色搭配 + * + * @param query + * @returnN + */ + public List productColorMatch(ProductColorDTO query) { + log.info("app端商品颜色搭配入参###{}",JSON.toJSONString(query)); + //获取该用户所有店铺下所有商品 + //查询用户店铺 + List storeVOS = storeService.queryUserStore(null,null); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + List dataBase = CollectionUtil.isEmpty(productIds)? Lists.newArrayList() : tProductMapper.selectBatchIds(productIds); + if(CollectionUtils.isEmpty(dataBase) || dataBase.size() <= 5){ + //商品数不够 不支持相似度搭配 + return Lists.newArrayList(); + } + AppProductColorExtractVO rgbObject= query.getProductRgbList().get(0); + List hsv = pythonService.rgb2hsv(Integer.valueOf(rgbObject.getR()),Integer.valueOf(rgbObject.getG()),Integer.valueOf(rgbObject.getB())); + if(CollectionUtils.isEmpty(hsv) ){ + //hsv查询不到 + return Lists.newArrayList(); + } + PantoneVO pantoneVO = panToneService.getByHSV(hsv.get(0),hsv.get(1),hsv.get(2)); + if(Objects.isNull(pantoneVO)){ + return Lists.newArrayList(); + } + dataBase = dataBase.stream().filter(data -> !StringUtils.isEmpty(data.getColor()) && data.getColor().equals(pantoneVO.getTcx())).collect(Collectors.toList()); + if(CollectionUtils.isEmpty(dataBase)){ + //匹配不到 + return Lists.newArrayList(); + } + + Map productIdToUrlMap = + CollectionUtil.emptyIfNull(dataBase).stream().collect(Collectors.toMap(TProduct::getId,TProduct::getPictureUrl)); + + Map> productToLabelMap = productLabelService.findByProductIds(dataBase.stream().map(TProduct::getId).collect(Collectors.toList())); + List labelIds = productToLabelMap.values() + .stream() + .map(list->list.stream().map(TProductLabel::getLabelId).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + //标签map + Map labelMap = labelService.queryMapByIds(labelIds); + return CopyUtil.copyList(dataBase,AppNewProductVO.class,(oo,dd)->{ + dd.setId(oo.getId().toString()); + dd.setPictureUrl(productIdToUrlMap.get(oo.getId())); + dd.setProductLabelInfo(CopyUtil.copyList(productToLabelMap.get(oo.getId()),ProductLabelVO.class,(o,d) ->{ + d.setId(o.getLabelId().toString()); + d.setName(labelMap.get(o.getLabelId()).getName()); + d.setType(labelMap.get(o.getLabelId()).getType()); + })); + }); + } + /** + * 商品颜色搭配 + * + * @param query + * @returnN + */ + public List colorExtract(ProductColorExtratDTO query) { + //等python接口 + List> lists = pythonService.colorExtract("color_extract",query.getPictureUrl(),0); + return lists.stream().map(list->new AppProductColorExtractVO(list.get(0),list.get(1),list.get(2))).collect(Collectors.toList()); + } + /** + * app分页查询新品列表 + * + * @param query + * @returnN + */ + public PageBaseResponse searchProductPage(SearchProductPageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!StringUtils.isEmpty(query.getStoreId())) { + List productIds= tProductStockService.findByStoreIds(Collections.singletonList(query.getStoreId())); + if(CollectionUtils.isEmpty(productIds)){ + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIds); + }else{ + //查询用户店铺 + List storeVOS = storeService.queryUserStore(null, null); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + if (CollectionUtils.isEmpty(productIds)) { + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIds); + } + if (!org.springframework.util.StringUtils.isEmpty(query.getLabelItem())) { + List productIds = tProductAttributeService.findByItemAndType(query.getLabelItem(), query.getLabelTypeMap()); + if (CollectionUtils.isEmpty(productIds)) { + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIds); + } + + //上架 + queryWrapper.eq("on_sale_state", 1); + queryWrapper.eq("upload_state", 1); + queryWrapper.orderByDesc("id"); + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if (CollectionUtils.isEmpty(page.getRecords())) { + return PageBaseResponse.success(new Page<>()); + } + List productIds = page.getRecords().stream().map(TProduct::getId).collect(Collectors.toList()); + Map> productToLabelMap = productLabelService.findByProductIds(productIds); + List labelIds = productToLabelMap.values() + .stream() + .map(list->list.stream().map(TProductLabel::getLabelId).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + //标签map + Map labelMap = labelService.queryMapByIds(labelIds); + IPage convert = page.convert((Function) + product -> + { + AppNewProductVO result = CopyUtil.copyObject(product, AppNewProductVO.class); + result.setId(product.getId().toString()); + result.setProductLabelInfo(CopyUtil.copyList(productToLabelMap.get(product.getId()),ProductLabelVO.class,(o,d) ->{ + d.setId(o.getLabelId().toString()); + d.setName(labelMap.get(o.getLabelId()).getName()); + d.setType(labelMap.get(o.getLabelId()).getType()); + })); + return result; + }); + return PageBaseResponse.success(convert); + } + private List findByBatchId(String batchId, Long accountId ) { + QueryWrapper query = new QueryWrapper<>(); + query.eq("batch_id", batchId); + query.eq("account_id", accountId); + query.eq("upload_state", 0); + return tProductMapper.selectList(query); + } + + /** + * 上传文件-新增用 + * + * @param md5 + * @param file + * @return + */ + @Transactional + public AppProductSingleUploadVo singleUploadProduct(MultipartFile file, String md5) { + Long accountId = UserContext.getUserHolder().getId(); + //上传路径 + String path = calculateFileUrl(accountId); + File fileNew = FileUtil.upload(file, path); + String url = fileNew.getAbsolutePath(); + String linuxDomain = fileProperties.getLinuxDomain(); + if (!StringUtils.isEmpty(linuxDomain)) { + //linux 系统 + String oldPath = fileProperties.getSys().getPath(); + url = url.replace(oldPath, linuxDomain); + } + String prefix = fileNew.getName().substring(0, fileNew.getName().lastIndexOf(".")); + return new AppProductSingleUploadVo(url, prefix, md5); + } + private String calculateFileUrl(Long userId) { + String rootPath = fileProperties.getSys().getPath(); + String day = DateUtil.dateToStr(new Date(), DateUtil.YYYYMM); + return rootPath + day + File.separator + "userFile" + File.separator + "appProduct" + + File.separator + userId + File.separator + UUID.randomUUID().toString(); + } + +} diff --git a/src/main/java/com/mixi/service/TAttributeTypeService.java b/src/main/java/com/mixi/service/TAttributeTypeService.java new file mode 100644 index 0000000..fd33374 --- /dev/null +++ b/src/main/java/com/mixi/service/TAttributeTypeService.java @@ -0,0 +1,99 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.mixi.common.utils.CopyUtil; +import com.mixi.mapper.TAttributeTypeMapper; +import com.mixi.mapper.entity.TAttributeType; +import com.mixi.mapper.entity.TProductAttribute; +import com.mixi.mapper.entity.TStore; +import com.mixi.model.vo.AttributeTypeVO; +import com.mixi.model.vo.AttributeVO; +import com.mixi.model.vo.AttributeValueVO; +import com.mixi.model.vo.StoreVO; +import lombok.extern.slf4j.Slf4j; +import org.checkerframework.checker.units.qual.A; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +/** + *

+ * 属性类型表 服务类 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Slf4j +@Service +public class TAttributeTypeService extends ServiceImpl { + @Resource + private TAttributeTypeMapper tAttributeTypeMapper; + @Resource + private TAttributeValueService tAttributeValueService; + + public Map resolveItemToValueMap(){ + Map itemToValueMap = Maps.newHashMap(); + itemToValueMap.put("top","2"); + itemToValueMap.put("bottom","14"); + itemToValueMap.put("dress","36"); + itemToValueMap.put("outer","38"); + itemToValueMap.put("jumpsuit","62"); + return itemToValueMap; + } + /** + * 查询所有属性值 + * @return + */ + public List queryAll(){ + //初始化一级标签对应的类型id map + Map itemToValueMap = resolveItemToValueMap(); + + QueryWrapper queryWrapper = new QueryWrapper<>(); + List result = Lists.newArrayList(); + List all = tAttributeTypeMapper.selectList(queryWrapper); + Map> groupMap = CollectionUtil.emptyIfNull(all) + .stream() + .collect(Collectors.groupingBy(TAttributeType::getLabelItem, + Collectors.mapping(v ->{ + AttributeTypeVO resultType =CopyUtil.copyObject(v,AttributeTypeVO.class); + resultType.setId(v.getId().toString()); + return resultType; + },Collectors.toList()))); + if(CollectionUtil.isEmpty(groupMap)){ + return result; + } + Map> valueMap = CollectionUtil.emptyIfNull(tAttributeValueService.queryAll()) + .stream() + .collect(Collectors.groupingBy(AttributeValueVO::getAttributeTypeId, + Collectors.mapping(AttributeValueVO::getAttributeValue,Collectors.toList()))); + groupMap.forEach((k,v)->{ + List attributeTypeVOS = groupMap.get(k); + result.add(new AttributeVO(k, StringUtils.isEmpty(itemToValueMap.get(k))?null :valueMap.get(itemToValueMap.get(k)), attributeTypeVOS)); + attributeTypeVOS.forEach(attributeTypeVO -> { + attributeTypeVO.setAttributeValueList(valueMap.get(attributeTypeVO.getId())); + }); + }); + return result; + } + /** + * 根据productIds查询 + * @param productIds + * @return + */ + public List findByProductIds(List productIds){ + QueryWrapper query = new QueryWrapper<>(); + query.in("product_id",productIds); + return tAttributeTypeMapper.selectList(query); + } +} diff --git a/src/main/java/com/mixi/service/TAttributeValueService.java b/src/main/java/com/mixi/service/TAttributeValueService.java new file mode 100644 index 0000000..da3beee --- /dev/null +++ b/src/main/java/com/mixi/service/TAttributeValueService.java @@ -0,0 +1,51 @@ +package com.mixi.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mixi.common.utils.CopyUtil; +import com.mixi.mapper.TAttributeValueMapper; +import com.mixi.mapper.entity.TAttributeType; +import com.mixi.mapper.entity.TAttributeValue; +import com.mixi.model.vo.AttributeValueVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + *

+ * 属性值表(对应python识别的标签信息) 服务类 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Slf4j +@Service +public class TAttributeValueService extends ServiceImpl { + @Resource + private TAttributeValueMapper tAttributeValueMapper; + + /** + * 查询所有属性值 + * + * @return + */ + public List queryAll() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + return CopyUtil.copyList(tAttributeValueMapper.selectList(queryWrapper), AttributeValueVO.class,(o,d)->{ + d.setAttributeTypeId(o.getAttributeTypeId().toString()); + }); + } + public void initData(){ + QueryWrapper query = new QueryWrapper<>(); + List result = tAttributeValueMapper.selectList(query); + result.forEach(value->{ + String attributeValue = value.getAttributeValue().trim(); + String frist = attributeValue.substring(0,1).toUpperCase(); + value.setAttributeValue(frist+attributeValue.substring(1)); + }); + this.updateBatchById(result); + } +} diff --git a/src/main/java/com/mixi/service/TCustomBuriedPointRecordService.java b/src/main/java/com/mixi/service/TCustomBuriedPointRecordService.java new file mode 100644 index 0000000..31c2afe --- /dev/null +++ b/src/main/java/com/mixi/service/TCustomBuriedPointRecordService.java @@ -0,0 +1,98 @@ +package com.mixi.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.mixi.common.utils.CopyUtil; +import com.mixi.common.utils.DateUtil; +import com.mixi.mapper.TCustomBuriedPointRecordMapper; +import com.mixi.mapper.entity.TCustomBuriedPointRecord; +import com.mixi.mapper.entity.TCustomRegister; +import com.mixi.mapper.entity.TStore; +import com.mixi.model.dto.CustomBuriedPointDTO; +import com.mixi.model.dto.CustomLogoutDTO; +import com.mixi.model.dto.QueryProductRankDTO; +import com.mixi.model.vo.AppProductSaleRankVO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.RequestBody; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +/** + *

+ * 客户埋点记录表 服务实现类 + *

+ * + * @author yanglei + * @since 2023-04-01 + */ +@Service +public class TCustomBuriedPointRecordService extends ServiceImpl { + + @Resource + private TCustomBuriedPointRecordMapper tCustomBuriedPointRecordMapper; + + + public static final List buriedPointType = Arrays.asList("BROWSE","PURCHASE"); + /** + * 客户数据埋点 + * + * @param customBuriedPointDTO + * @return + */ + @Transactional + public void buriedPoint(CustomBuriedPointDTO customBuriedPointDTO) { + Assert.isTrue(buriedPointType.contains(customBuriedPointDTO.getType()),"Unknown type !"); + TCustomBuriedPointRecord save = TCustomBuriedPointRecord.builder() + .type(customBuriedPointDTO.getType()) + .customId(Long.valueOf(customBuriedPointDTO.getCustomId())) + .accountId(Long.valueOf(customBuriedPointDTO.getAccountId())) + .storeId(Long.valueOf(customBuriedPointDTO.getStoreId())) + .productId(Long.valueOf(customBuriedPointDTO.getProductId())) + .createDate(DateUtil.getByTimeZone(customBuriedPointDTO.getTimeZone())).build(); + this.save(save); + } + + /** + * 获取个性化商品 + * + * @param type + * @return + */ + public List getRecommendProduct(String type) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("type",type); + return tCustomBuriedPointRecordMapper.selectList(queryWrapper); + } + + /** + * 商品销量排行,先取前10,按照 日 ,周 ,月 + * + * @param query + * @return + */ + public List queryProductSaleRank(QueryProductRankDTO query) { + QueryWrapper wrapper = new QueryWrapper(); + wrapper.select("count(*) as id, product_id"); + wrapper.ge("create_date",new Date(query.getCreateDateStart())); + wrapper.le("create_date",new Date(query.getCreateDateEnd())); + wrapper.eq("store_id",Long.valueOf(query.getStoreId())); + wrapper.eq("type","PURCHASE"); + wrapper.groupBy("product_id"); + wrapper.last("order by count(*) desc limit 10"); + List result = tCustomBuriedPointRecordMapper.selectList(wrapper); + return CopyUtil.copyList(result,AppProductSaleRankVO.class,(o,d) ->{ + d.setId(o.getProductId().toString()); + d.setTotal(o.getId().toString()); + }); + } + +} diff --git a/src/main/java/com/mixi/service/TCustomRegisterService.java b/src/main/java/com/mixi/service/TCustomRegisterService.java new file mode 100644 index 0000000..73a1405 --- /dev/null +++ b/src/main/java/com/mixi/service/TCustomRegisterService.java @@ -0,0 +1,96 @@ +package com.mixi.service; + +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mixi.common.utils.DateUtil; +import com.mixi.mapper.TCustomRegisterMapper; +import com.mixi.mapper.entity.TAccount; +import com.mixi.mapper.entity.TCustomRegister; +import com.mixi.mapper.entity.TRole; +import com.mixi.model.dto.CustomLogoutDTO; +import com.mixi.model.dto.CustomRegisterDTO; +import com.mixi.model.vo.CustomRegisterVO; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import javax.annotation.Resource; +import java.util.Objects; + +/** + *

+ * 客户登入记录表 服务实现类 + *

+ * + * @author yanglei + * @since 2023-04-01 + */ +@Service +public class TCustomRegisterService extends ServiceImpl { + @Resource + private TCustomRegisterMapper customRegisterMapper; + + /** + * 客户登记 + * + * @param customRegisterDTO + * @return + */ + @Transactional + public CustomRegisterVO register(CustomRegisterDTO customRegisterDTO) { + CustomRegisterVO response = new CustomRegisterVO(); + //校验 + TCustomRegister register = getOneByPhone(customRegisterDTO.getPhone()); + if(Objects.nonNull(register)){ + //校验已登入 + Assert.isTrue(!( register.getState() ==1 + && !register.getAccountId().toString().equals(customRegisterDTO.getAccountId()) ),"Customer logged in !"); + register.setAccountId(Long.valueOf(customRegisterDTO.getAccountId())); + register.setState(1); + register.setUpdateDate(DateUtil.getByTimeZone(customRegisterDTO.getTimeZone())); + this.updateById(register); + + response.setId(register.getId().toString()); + response.setPhone(register.getPhone()); + }else{ + //新增 + TCustomRegister save =TCustomRegister.builder() + .accountId(Long.valueOf(customRegisterDTO.getAccountId())) + .state(1) + .createDate(DateUtil.getByTimeZone(customRegisterDTO.getTimeZone())) + .storeId(Long.valueOf(customRegisterDTO.getStoreId())) + .phone(customRegisterDTO.getPhone()).build(); + this.save(save); + + response.setId(save.getId().toString()); + response.setPhone(save.getPhone()); + } + return response; + } + /** + * 客户登出 + * + * @param customLogoutDTO + * @return + */ + @Transactional + public void logout(CustomLogoutDTO customLogoutDTO) { + TCustomRegister tCustomRegister = customRegisterMapper.selectById(customLogoutDTO.getCustomId()); + Assert.notNull(tCustomRegister,"Custom not registered!"); + //校验已登入 + Assert.isTrue(tCustomRegister.getState() ==1 ,"Customer logged out!"); + tCustomRegister.setState(0); + tCustomRegister.setUpdateDate(DateUtil.getByTimeZone(customLogoutDTO.getTimeZone())); + this.updateById(tCustomRegister); + } + private TCustomRegister getOneByPhone(String phone) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("phone", phone); + return customRegisterMapper.selectOne(queryWrapper); + } + + + +} diff --git a/src/main/java/com/mixi/service/TProductAssortmentService.java b/src/main/java/com/mixi/service/TProductAssortmentService.java new file mode 100644 index 0000000..6db8ca9 --- /dev/null +++ b/src/main/java/com/mixi/service/TProductAssortmentService.java @@ -0,0 +1,87 @@ +package com.mixi.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.mixi.mapper.TProductAssortmentMapper; +import com.mixi.mapper.entity.TProduct; +import com.mixi.mapper.entity.TProductAssortment; +import com.mixi.mapper.entity.TProductLabel; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +/** + *

+ * 商品搭配表 服务类 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Slf4j +@Service +public class TProductAssortmentService extends ServiceImpl { + @Resource + private TProductAssortmentMapper tProductAssortmentMapper; + @Resource + private TProductService tProductService; + + public void deleteByProductId(String productId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("product_id", productId); + tProductAssortmentMapper.delete(queryWrapper); + } + public void deleteByAssortmentProductId(String productId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("assortment_product_id", productId); + List tProductAssortments = tProductAssortmentMapper.selectList(queryWrapper); + if(CollectionUtils.isEmpty(tProductAssortments)){ + return; + } + Map> maps = tProductAssortments.stream().collect(Collectors.groupingBy(TProductAssortment::getProductId)); + maps.forEach((k,v)->{ + List coverSorts = v.stream().map(TProductAssortment::getCoverSort).collect(Collectors.toList()); + QueryWrapper deleteWrapper = new QueryWrapper<>(); + deleteWrapper.eq("product_id", k); + deleteWrapper.in("cover_sort", coverSorts); + tProductAssortmentMapper.delete(deleteWrapper); + }); + } + public List findByProductIds(List productIds) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("product_id", productIds); + return tProductAssortmentMapper.selectList(queryWrapper); + } + public List findByUseProductIdsNum(List productIds, Map productIdToPriceMap) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("product_id", productIds); + List productAssortments = tProductAssortmentMapper.selectList(queryWrapper); + if(CollectionUtils.isEmpty(productAssortments)){ + return Lists.newArrayList(); + } + //查询库存大于0的搭配 + List assortmentProductIds = productAssortments.stream().map(TProductAssortment::getAssortmentProductId).collect(Collectors.toList()); + List countUseProducts = tProductService.getUseProductNum(assortmentProductIds); + if(CollectionUtils.isEmpty(countUseProducts)){ + return Lists.newArrayList(); + } + Map map = countUseProducts.stream().collect(Collectors.toMap(TProduct::getId,TProduct::getPrice)); + Map mapUrl = countUseProducts.stream().collect(Collectors.toMap(TProduct::getId,TProduct::getPictureUrl)); + map.forEach(productIdToPriceMap::put); + productAssortments.forEach(assortment ->assortment.setGeneratePictureUrl(mapUrl.get(assortment.getAssortmentProductId()))); + return productAssortments.stream().filter(f ->map.containsKey(f.getAssortmentProductId())).collect(Collectors.toList()); + } + public List findByIds(List ids) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("id", ids); + return tProductAssortmentMapper.selectList(queryWrapper); + } +} diff --git a/src/main/java/com/mixi/service/TProductAttributeService.java b/src/main/java/com/mixi/service/TProductAttributeService.java new file mode 100644 index 0000000..837a79e --- /dev/null +++ b/src/main/java/com/mixi/service/TProductAttributeService.java @@ -0,0 +1,120 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.map.MapUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.mixi.mapper.TProductAttributeMapper; +import com.mixi.mapper.entity.*; +import io.netty.util.internal.StringUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +/** + *

+ * 商品属性关联表 服务类 + *

+ * + * @author yanglei + * @since 2023-03-19 + */ +@Service +public class TProductAttributeService extends ServiceImpl { + @Resource + private TProductAttributeMapper tProductAttributeMapper; + @Resource + private TAttributeTypeService tAttributeTypeService; + + /** + * 根据productId查询 + * @param productIds + * @return + */ + public List findByProductIds(List productIds){ + QueryWrapper query = new QueryWrapper<>(); + query.in("product_id",productIds); + return tProductAttributeMapper.selectList(query); + } + /** + * 获取商品所属标签的item值 + * @param productIds + * @return + */ + public Map findByProductAttributesItem(List productIds){ + List tProductAttributes = findByProductIds(productIds); + Map productToAttributeTypeIdMap = CollectionUtil.emptyIfNull(tProductAttributes).stream().collect( + Collectors.groupingBy(TProductAttribute::getProductId, + Collectors.collectingAndThen(Collectors.toList(),list ->list.get(0).getAttributeItem()))); + return productToAttributeTypeIdMap; + } + public void deleteByProductId(String productId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("product_id", productId); + tProductAttributeMapper.delete(queryWrapper); + } + + public List findByItemAndType(String attributeItem,Map> labelTypeMap) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("attribute_item", attributeItem); + if(MapUtil.isNotEmpty(labelTypeMap)){ + labelTypeMap.forEach((k,v)->{ +// queryWrapper.in("attribute_type",Lists.newArrayList(labelTypeMap.keySet())); +// queryWrapper.in("attribute_value", labelTypeMap.values().stream().flatMap(List::stream).collect(Collectors.toList())); + queryWrapper.or(wrapper -> wrapper + .eq("attribute_type",k) + .in("attribute_value", v)); + }); + } + List result = tProductAttributeMapper.selectList(queryWrapper); + return calculateProductId(result,labelTypeMap); + } + private List calculateProductId(List result,Map> labelTypeMap){ + if(CollectionUtils.isEmpty(result)){ + return null; + } + if(MapUtil.isEmpty(labelTypeMap)){ + return result.stream().map(TProductAttribute::getProductId).distinct().collect(Collectors.toList()); + } + List returnProductIds = Lists.newArrayList(); + Map> groupMap = result.stream().collect(Collectors.groupingBy(TProductAttribute::getProductId)); + groupMap.forEach((k,v)->{ + AtomicReference exsit = new AtomicReference<>(true); + Map> groupAttributeTypeMap = v.stream().collect( + Collectors.collectingAndThen(Collectors.groupingBy(TProductAttribute::getAttributeType),map->{ + Map> newMap = Maps.newHashMap(); + map.forEach((k2,v2)->{ + newMap.put(k2,v2.stream().map(TProductAttribute::getAttributeValue).collect(Collectors.toList())); + }); + return newMap; + })); + labelTypeMap.forEach((k1,v1)->{ + List attributeList= groupAttributeTypeMap.get(k1); + if(CollectionUtils.isEmpty(attributeList)){ + exsit.set(false); + return; + } + if(CollectionUtils.isEmpty(v1)){ + return; + } + v1.forEach(v11->{ + if(StringUtils.isNotBlank(v11) && !attributeList.contains(v11)){ + exsit.set(false); + } + }); + }); + if(exsit.get()){ + returnProductIds.add(k); + } + }); + return returnProductIds; + } +} diff --git a/src/main/java/com/mixi/service/TProductBatchService.java b/src/main/java/com/mixi/service/TProductBatchService.java new file mode 100644 index 0000000..641a5eb --- /dev/null +++ b/src/main/java/com/mixi/service/TProductBatchService.java @@ -0,0 +1,50 @@ +package com.mixi.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mixi.common.utils.DateUtil; +import com.mixi.mapper.TProductBatchMapper; +import com.mixi.mapper.entity.TProductBatch; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.commons.CommonsMultipartFile; + +import javax.annotation.Resource; + + +/** + *

+ * 商品批次表 服务类 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Slf4j +@Service +public class TProductBatchService extends ServiceImpl { + + @Resource + private TProductBatchMapper tProductBatchMapper; + +// /** +// * 添加批次 +// * @param batchProductTotal +// */ +// public TProductBatch saveProductBatch(Integer batchProductTotal,String timeZone){ +// TProductBatch save = TProductBatch.builder() +// .batchProductTotal(batchProductTotal) +// .createDate(DateUtil.getByTimeZone(timeZone)).build(); +// save(save); +// return save; +// } +// +// /** +// * 根据id查询 +// * @param id +// * @return +// */ +// public TProductBatch findById(String id){ +// return tProductBatchMapper.selectById(id); +// } + +} diff --git a/src/main/java/com/mixi/service/TProductService.java b/src/main/java/com/mixi/service/TProductService.java new file mode 100644 index 0000000..8ef5c88 --- /dev/null +++ b/src/main/java/com/mixi/service/TProductService.java @@ -0,0 +1,1903 @@ +package com.mixi.service; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.map.MapUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson2.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.mixi.common.config.FileProperties; +import com.mixi.common.config.exception.BusinessException; +import com.mixi.common.context.UserContext; +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.tasks.mituExportEntity.MiTuProductStock; +import com.mixi.common.utils.*; +import com.mixi.common.utils.export.ProductCellWriteHandler; +import com.mixi.mapper.MiTuProductMapper; +import com.mixi.mapper.TProductAssortmentMapper; +import com.mixi.mapper.TProductMapper; +import com.mixi.mapper.TStoreMapper; +import com.mixi.mapper.entity.*; +import com.mixi.model.dto.*; +import com.mixi.model.vo.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.*; +import java.util.*; +import java.util.Date; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static com.mixi.common.utils.DateUtil.YYYY_MM_DD_HH_MM_SS; + + +/** + *

+ * 商品表 服务类 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Slf4j +@Service +public class TProductService extends ServiceImpl { + + @Resource + private TProductBatchService tProductBatchService; + @Resource + private FileProperties fileProperties; + @Resource + private ProductLabelService productLabelService; + @Resource + private LabelService labelService; + @Resource + private StoreService storeService; + @Resource + private RoleService roleService; + @Resource + private TProductStockService tProductStockService; + @Resource + private TProductAssortmentService tProductAssortmentService; + @Resource + private TProductAssortmentMapper productAssortmentMapper; + @Resource + private TProductAttributeService tProductAttributeService; + @Resource + private TProductMapper tProductMapper; + @Resource + private PythonService pythonService; + @Resource + private AccountService accountService; + @Resource + private PanToneService panToneService; + @Resource + private TStoreMapper tStoreMapper; + // JDBC 驱动器名称以及数据库 URL + static final String JDBC_DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver"; + static final String DB_URL = "jdbc:sqlserver://118.142.0.178:1550;databaseName=Hayman_prod"; + + // 数据库凭据 + static final String USER = "user01"; + static final String PASS = "haySIS-0522"; + + @Resource + private MinioUtil minioUtil; + + /** + * 分页查询商品,根据用户所在店铺去查,不能只查当前用户的商品 + * + * @param query + * @returnN + */ + public PageBaseResponse queryProductPage(QueryProductPageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + List productIdsQuery = resolveConditionProductIds(query); + if (CollectionUtils.isEmpty(productIdsQuery)) { + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIdsQuery); + if (Objects.nonNull(query.getCreateDateStart())) { + queryWrapper.ge("create_date", new Date(query.getCreateDateStart())); + } + if (Objects.nonNull(query.getCreateDateEnd())) { + queryWrapper.le("create_date", new Date(query.getCreateDateEnd())); + } + if (Objects.nonNull(query.getOnSaleState())) { + queryWrapper.eq("on_sale_state", query.getOnSaleState()); + } + queryWrapper.eq("upload_state", 1); + //排序算法 + if(!CollectionUtils.isEmpty(query.getColumnSortList())){ + query.getColumnSortList().forEach(columnSortDTO -> { + if(!Arrays.asList("asc","desc").contains(columnSortDTO.getStyle())){ + throw new BusinessException("Column sorting style error!"); + } + if("asc".equals(columnSortDTO.getStyle())){ + //正序 + queryWrapper.orderByAsc(columnSortDTO.getColumn()); + }else{ + //倒序 + queryWrapper.orderByDesc(columnSortDTO.getColumn()); + } + }); + }else{ + //默认倒序 + queryWrapper.orderByDesc("id"); + } + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if (CollectionUtils.isEmpty(page.getRecords())) { + return PageBaseResponse.success(new Page<>()); + } + List productIds = page.getRecords().stream().map(TProduct::getId).collect(Collectors.toList()); + Map> productToLabelMap = productLabelService.findByProductIds(productIds); + List labelIds = productToLabelMap.values() + .stream() + .map(list -> list.stream().map(TProductLabel::getLabelId).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + //标签map + Map labelMap = labelService.queryMapByIds(labelIds); + List tProductAttributes = tProductAttributeService.findByProductIds(productIds); + Map>>> attributeMap2 = tProductAttributes.stream().collect( + Collectors.groupingBy(TProductAttribute::getProductId, + Collectors.groupingBy(TProductAttribute::getAttributeItem, + Collectors.collectingAndThen(Collectors.groupingBy(v -> v.getAttributeType()), map -> { + Map> newMap = Maps.newHashMap(); + map.forEach((k, v) ->{ + //去重 + List attributeType = v.stream().map(pro->{ + List list= Arrays.asList(pro.getAttributeValue().split(",")); + list = Lists.newArrayList(Sets.newConcurrentHashSet(list)); + return String.join(",",list); + }).collect(Collectors.toList()); + //去重 + newMap.put(k, Lists.newArrayList(Sets.newConcurrentHashSet(attributeType))); + }); + return newMap; + })))); + //门店 + List productStocks = tProductStockService.findByProductIds(productIds); + Map> productToStoreMap = productStocks.stream().collect(Collectors.groupingBy(TProductStock::getProductId)); + List stockIds = productStocks.stream().map(TProductStock::getStoreId).collect(Collectors.toList()); + List tStores = storeService.queryByStoreIds(stockIds); + Map storeIdToNameMap = CollectionUtil.isEmpty(tStores) ? Maps.newHashMap() : + tStores.stream().collect(Collectors.toMap(StoreVO::getId, StoreVO::getName)); + //搭配 + Map productIdToPriceMap = Maps.newHashMap(); + List tProductAssortments = tProductAssortmentService.findByUseProductIdsNum(productIds,productIdToPriceMap); + Map> tProductAssortmentsMap = + CollectionUtil.emptyIfNull(tProductAssortments).stream().collect(Collectors.groupingBy(TProductAssortment::getProductId)); + IPage convert = page.convert((Function) + product -> + { + ProductVO result = CopyUtil.copyObject(product, ProductVO.class); + result.setId(product.getId().toString()); + result.setOnSaleStateName(result.getOnSaleState() == 1 ? "上架" : "下架"); + result.setCreateDate(product.getCreateDate().getTime()); + result.setProductLabelInfo(CopyUtil.copyList(productToLabelMap.get(product.getId()), ProductLabelVO.class, (o, d) -> { + d.setId(o.getLabelId().toString()); + d.setName(labelMap.get(o.getLabelId()).getName()); + d.setType(labelMap.get(o.getLabelId()).getType()); + })); + result.setAttributeItemInfo(resolveAttribute(attributeMap2.get(product.getId()))); + result.setStoreInfoList(resolveStoreInfo(productToStoreMap.get(product.getId()), storeIdToNameMap)); + result.setAssortmentList(resolveProductAssortmentInfo(tProductAssortmentsMap.get(product.getId()), productIdToPriceMap)); + result.setPictureUrl(minioUtil.getPresignedUrl(result.getPictureUrl(), 24 * 60)); + return result; + }); + return PageBaseResponse.success(convert); + } + + private List resolveConditionProductIds(QueryProductPageDTO query){ + List productIds1 = Lists.newArrayList(); + List productIds2 = Lists.newArrayList(); + List productIds3 = Lists.newArrayList(); + if (!CollectionUtils.isEmpty(query.getProductLabelIds())) { + List productIds = productLabelService.findByLabelIds(query.getProductLabelIds()); + if (CollectionUtils.isEmpty(productIds)) { + return null; + } + productIds1.addAll(productIds); + } + if (!org.springframework.util.StringUtils.isEmpty(query.getLabelItem())) { + List productIds = tProductAttributeService.findByItemAndType(query.getLabelItem(), query.getLabelTypeMap()); + if (CollectionUtils.isEmpty(productIds)) { + return null; + } + productIds2.addAll(productIds); + } + if (!CollectionUtils.isEmpty(query.getStoreIds())) { + List productIds = tProductStockService.findByStoreIds(query.getStoreIds()); + if (CollectionUtils.isEmpty(productIds)) { + return null; + } + productIds3.addAll(productIds); + } else { + //查询用户店铺 + List storeVOS = storeService.queryUserStore(null, null); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + if (CollectionUtils.isEmpty(productIds)) { + return null; + } + productIds3.addAll(productIds); + } + if (!CollectionUtils.isEmpty(productIds1) && !CollectionUtils.isEmpty(productIds2) && !CollectionUtils.isEmpty(productIds3)){ + return CollectionUtil.intersection(productIds1,productIds2,productIds3).stream().collect(Collectors.toList()); + }else if (!CollectionUtils.isEmpty(productIds2) && !CollectionUtils.isEmpty(productIds3)){ + return CollectionUtil.intersection(productIds2,productIds3).stream().collect(Collectors.toList()); + }else if (!CollectionUtils.isEmpty(productIds1) && !CollectionUtils.isEmpty(productIds2)){ + return CollectionUtil.intersection(productIds1,productIds2).stream().collect(Collectors.toList()); + }else if (!CollectionUtils.isEmpty(productIds1) && !CollectionUtils.isEmpty(productIds3)){ + return CollectionUtil.intersection(productIds1,productIds3).stream().collect(Collectors.toList()); + }else if (!CollectionUtils.isEmpty(productIds1) ){ + return productIds1; + }else if (!CollectionUtils.isEmpty(productIds2) ){ + return productIds2; + }else if (!CollectionUtils.isEmpty(productIds3) ){ + return productIds3; + } + return null; + } + /** + * 导出商品 + * + * @param query + * @returnN + */ + public String exportProduct(QueryProductPageDTO query) throws IOException { + Long accountId = UserContext.getUserHolder().getId(); + List> datas = new ArrayList<>(); + //列 + List list2 = new ArrayList<>(); + list2.add("Product Label"); + list2.add("Label Item"); + list2.add("Label Type"); + list2.add("Retail Price"); + list2.add("Color"); + list2.add("Store Name"); + list2.add("XS"); + list2.add("S"); + list2.add("M"); + list2.add("L"); + list2.add("XL"); + list2.add("XXL"); + list2.add("Add Time"); + list2.add("On Sale State"); + + int size = list2.size(); + datas.add(list2); + + String url = calculateExportFileUrl(accountId); +// String url = "D:\\upload\\mixi\\"; + File file = new File(url); + if(!file.exists()){ + file.mkdir(); + } + String filePath = url+System.currentTimeMillis()+".xlsx"; + //合并设置,先不设置 + OnceAbsoluteMergeStrategy strategy0 = new OnceAbsoluteMergeStrategy(0, 0, 0, size - 1); + OnceAbsoluteMergeStrategy strategy1 = new OnceAbsoluteMergeStrategy(1, 1, 0, size - 1); + ExcelWriter excelWriter = EasyExcel.write(filePath) + //.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + .build(); + ExcelWriterSheetBuilder builder = EasyExcel.writerSheet(0, "Export Product"); +// builder = builder.registerWriteHandler(strategy0); +// builder = builder.registerWriteHandler(strategy1); + ProductCellWriteHandler productCellWriteHandler = new ProductCellWriteHandler(); + builder = builder.registerWriteHandler(productCellWriteHandler); + WriteSheet writeSheet = builder.build(); + + QueryProductPageDTO pageQuery= CopyUtil.copyObject(query,QueryProductPageDTO.class); + pageQuery.setPage(1); + pageQuery.setSize(100); + List productIds = resolveConditionProductIds(query); + if (!CollectionUtils.isEmpty(productIds)){ + //计算总属性个数 + List productAttributes = tProductAttributeService.findByProductIds(productIds); + List attributeTypeList = Lists.newArrayList(new HashSet(productAttributes.stream().map(TProductAttribute::getAttributeType).collect(Collectors.toList()))); + list2.addAll(attributeTypeList); + excelWriter.write(datas, writeSheet); + while(true){ + PageBaseResponse pageBaseResponse = this.queryProductPage(pageQuery); + if(Objects.isNull(pageBaseResponse) || CollectionUtils.isEmpty( pageBaseResponse.getContent())){ + break; + } + //分批导出 + doExport(pageBaseResponse.getContent(),attributeTypeList, writeSheet, excelWriter); + pageQuery.setPage(pageQuery.getPage()+1); + } + }else { + excelWriter.write(datas, writeSheet); + } + //关闭 + excelWriter.finish(); + String linuxDomain = fileProperties.getLinuxDomain(); + if (!StringUtils.isEmpty(linuxDomain)) { + //linux 系统 + String oldPath = fileProperties.getSys().getPath(); + filePath = filePath.replace(oldPath, linuxDomain); + } + return filePath; + } + private String calculateExportFileUrl(Long userId) { + String rootPath = fileProperties.getSys().getPath(); + return rootPath + "exportFile" + File.separator + userId +File.separator; + } + private void doExport(List productVOS,List attributeTypeList,WriteSheet writeSheet,ExcelWriter excelWriter){ + List> datas = resolveProductExport(productVOS,attributeTypeList); + excelWriter.write(datas, writeSheet); + + } + private List> resolveProductExport(List productVOS,List attributeTypeList){ + List> datas = new ArrayList<>(); + + productVOS.forEach(productVO -> { + List storeInfoList = productVO.getStoreInfoList(); + if(CollectionUtils.isEmpty(storeInfoList)){ + List data = Lists.newArrayList(); + datas.add(data); + + List productLabelInfo = productVO.getProductLabelInfo(); + data.add(CollectionUtils.isEmpty(productLabelInfo)? + "" :productLabelInfo.stream().map(ProductLabelVO::getName).collect(Collectors.joining(",")) ); + + AttributeVO attributeItemInfo = productVO.getAttributeItemInfo(); + data.add(Objects.isNull(attributeItemInfo) ? "": String.join(",",attributeItemInfo.getLabelItem())); + data.add(Objects.isNull(attributeItemInfo) || CollectionUtils.isEmpty(attributeItemInfo.getLabelTypeValueList()) ? "" + : String.join(",",attributeItemInfo.getLabelTypeValueList())); + data.add("$"+productVO.getPrice()); + data.add(productVO.getColor()); + data.add(""); + data.add(""); + data.add(""); + data.add(""); + data.add(""); + data.add(""); + data.add(""); + data.add(DateUtil.dateToStr(new Date(),YYYY_MM_DD_HH_MM_SS)); + data.add(productVO.getOnSaleState() == 1 ?"Y" :"N"); + + //填充AttributeType数据 + getAttributeTypeExportData(attributeTypeList,Objects.isNull(attributeItemInfo) ? null :attributeItemInfo.getAttributeTypeList(),data); + }else{ + for (BatchUploadProductStoreDTO batchUploadProductStoreDTO : storeInfoList) { + List data = Lists.newArrayList(); + datas.add(data); + + List productLabelInfo = productVO.getProductLabelInfo(); + data.add(CollectionUtils.isEmpty(productLabelInfo)? + "" :productLabelInfo.stream().map(ProductLabelVO::getName).collect(Collectors.joining(",")) ); + + AttributeVO attributeItemInfo = productVO.getAttributeItemInfo(); + data.add(Objects.isNull(attributeItemInfo) ? "": String.join(",",attributeItemInfo.getLabelItem())); + data.add(Objects.isNull(attributeItemInfo) || CollectionUtils.isEmpty(attributeItemInfo.getLabelTypeValueList()) ? "" + : String.join(",",attributeItemInfo.getLabelTypeValueList())); + data.add("$"+productVO.getPrice()); + data.add(productVO.getColor()); + data.add(batchUploadProductStoreDTO.getStoreName()); + if(!CollectionUtils.isEmpty(batchUploadProductStoreDTO.getStock())){ + data.add(batchUploadProductStoreDTO.getStock().stream() + .filter(f->f.getSize().equals("XS")).map(stock->stock.getNum()+"").findFirst().orElse("0")); + data.add(batchUploadProductStoreDTO.getStock().stream() + .filter(f->f.getSize().equals("S")).map(stock->stock.getNum()+"").findFirst().orElse("0")); + data.add(batchUploadProductStoreDTO.getStock().stream() + .filter(f->f.getSize().equals("M")).map(stock->stock.getNum()+"").findFirst().orElse("0")); + data.add(batchUploadProductStoreDTO.getStock().stream() + .filter(f->f.getSize().equals("L")).map(stock->stock.getNum()+"").findFirst().orElse("0")); + data.add(batchUploadProductStoreDTO.getStock().stream() + .filter(f->f.getSize().equals("XL")).map(stock->stock.getNum()+"").findFirst().orElse("0")); + data.add(batchUploadProductStoreDTO.getStock().stream() + .filter(f->f.getSize().equals("XXL")).map(stock->stock.getNum()+"").findFirst().orElse("0")); + } + data.add(DateUtil.dateToStr(new Date(),YYYY_MM_DD_HH_MM_SS)); + data.add(productVO.getOnSaleState() == 1 ?"Y" :"N"); + //填充AttributeType数据 + getAttributeTypeExportData(attributeTypeList,Objects.isNull(attributeItemInfo) ? null :attributeItemInfo.getAttributeTypeList(),data); + } + } + + }); + return datas; + } + private void getAttributeTypeExportData(List attributeTypeList,List attributeTypeListVos,List data){ + attributeTypeList.forEach(attributeType->{ + if(CollectionUtils.isEmpty(attributeTypeListVos)){ + data.add(""); + }else{ + AttributeTypeVO attributeTypeVO = attributeTypeListVos.stream().filter(f->f.getLabelType().equals(attributeType)).findFirst().orElse(null); + if (Objects.nonNull(attributeTypeVO)){ + data.add(CollectionUtils.isEmpty(attributeTypeVO.getAttributeValueList())?"" : CollectionUtil.join(attributeTypeVO.getAttributeValueList(),",")); + }else { + data.add(""); + } + } + }); + } + + /** + * 查询商品详情 + * + * @param id + * @returnN + */ + public ProductVO detail(String id) { + TProduct tProduct = tProductMapper.selectById(id); + Assert.notNull(tProduct, "Unknown Product!"); + + Map> productToLabelMap = productLabelService.findByProductIds(Collections.singletonList(tProduct.getId())); + List labelIds = productToLabelMap.values() + .stream() + .map(list -> list.stream().map(TProductLabel::getLabelId).collect(Collectors.toList())) + .flatMap(List::stream).collect(Collectors.toList()); + //标签map + Map labelMap = labelService.queryMapByIds(labelIds); + List tProductAttributes = tProductAttributeService.findByProductIds(Collections.singletonList(tProduct.getId())); + //属性map + Map>> attributeMap = tProductAttributes.stream().collect( + Collectors.groupingBy(TProductAttribute::getAttributeItem, + Collectors.collectingAndThen(Collectors.groupingBy(TProductAttribute::getAttributeType), map -> { + Map> newMap = Maps.newHashMap(); + map.forEach((k, v) ->{ + //去重 + List attributeType = v.stream().map(pro->{ + List list= Arrays.asList(pro.getAttributeValue().split(",")); + list = Lists.newArrayList(Sets.newConcurrentHashSet(list)); + return String.join(",",list); + }).collect(Collectors.toList()); + //去重 + newMap.put(k, Lists.newArrayList(Sets.newConcurrentHashSet(attributeType))); + }); + return newMap; + }))); + //门店 + List productStocks = tProductStockService.findByProductIds(Collections.singletonList(tProduct.getId())); + List stockIds = productStocks.stream().map(TProductStock::getStoreId).collect(Collectors.toList()); + List tStores = storeService.queryByStoreIds(stockIds); + Map storeIdToNameMap = CollectionUtil.isEmpty(tStores) ? Maps.newHashMap() : + tStores.stream().collect(Collectors.toMap(StoreVO::getId, StoreVO::getName)); + //搭配 + Map productIdToPriceMap = Maps.newHashMap(); + List tProductAssortments = tProductAssortmentService.findByUseProductIdsNum(Collections.singletonList(tProduct.getId()),productIdToPriceMap); + ProductVO result = CopyUtil.copyObject(tProduct, ProductVO.class); + result.setId(tProduct.getId().toString()); + result.setOnSaleStateName(result.getOnSaleState() == 1 ? "上架" : "下架"); + result.setCreateDate(tProduct.getCreateDate().getTime()); + result.setProductLabelInfo(CopyUtil.copyList(productToLabelMap.get(tProduct.getId()), ProductLabelVO.class, (o, d) -> { + d.setId(o.getLabelId().toString()); + d.setName(labelMap.get(o.getLabelId()).getName()); + d.setType(labelMap.get(o.getLabelId()).getType()); + })); + result.setAttributeItemInfo(resolveAttribute(attributeMap)); + result.setStoreInfoList(resolveStoreInfo(productStocks, storeIdToNameMap)); + result.setAssortmentList(resolveProductAssortmentInfo(tProductAssortments,productIdToPriceMap)); + result.setPictureUrl(minioUtil.getPresignedUrl(result.getPictureUrl(), 24 * 60)); + return result; + } + + private List> resolveProductAssortmentInfo(List tProductAssortments,Map productIdToPriceMap) { + List> returnProducts = Lists.newArrayList(); + Map> tProductAssortmentsMap = CollectionUtil.emptyIfNull(tProductAssortments).stream().collect( + Collectors.groupingBy(TProductAssortment::getCoverSort)); + if(MapUtil.isEmpty(tProductAssortmentsMap)){ + return Lists.newArrayList(); + } + List keys = Lists.newArrayList(tProductAssortmentsMap.keySet()).stream().sorted().collect(Collectors.toList()); + keys.forEach(key ->{ + returnProducts.add(CopyUtil.copyList(tProductAssortmentsMap.get(key), ProductAssortmentVO.class,(o,d)->{ + d.setProductId(o.getAssortmentProductId()); + d.setPrice(productIdToPriceMap.get(d.getProductId())); + })); + }); + for (List returnProduct : returnProducts) { + for (ProductAssortmentVO productAssortmentVO : returnProduct) { + productAssortmentVO.setGeneratePictureUrl(minioUtil.getPresignedUrl(productAssortmentVO.getGeneratePictureUrl(), 24 * 60)); + } + } + return returnProducts; + } + + private List resolveStoreInfo(List productStocks, Map storeIdToNameMap) { + return productStocks.stream().map(store -> + new BatchUploadProductStoreDTO(store.getStoreId().toString(), storeIdToNameMap.get(store.getStoreId().toString()), + JSON.parseArray(store.getStockContent(), BatchUploadProductStoreStockDTO.class))) + .collect(Collectors.toList()); + } + + private AttributeVO resolveAttribute(Map>> attributeMap) { + AttributeVO attributeVO = new AttributeVO(); + if(MapUtil.isEmpty(attributeMap)){ + return attributeVO; + } + attributeMap.forEach((k, v) -> { + List attributeTypeList = Lists.newArrayList(); + attributeVO.setLabelItem(k); + attributeVO.setAttributeTypeList(attributeTypeList); + v.forEach((k1, v1) -> { + if (StringUtils.isEmpty(k1)) { + return; + } + AttributeTypeVO attributeTypeVO = new AttributeTypeVO(); + attributeTypeVO.setLabelType(k1); + attributeTypeVO.setAttributeValueList(v1); + attributeTypeList.add(attributeTypeVO); + }); + attributeVO.setLabelTypeValueList(resolveAttributeTypeList(attributeTypeList)); + }); + return attributeVO; + } + + private List resolveAttributeTypeList(List attributeTypeList) { + List attributeTypes = Arrays.asList("Type", "Subtype"); + return CollectionUtil.emptyIfNull(attributeTypeList) + .stream() + .filter(type -> attributeTypes.contains(type.getLabelType())) + .map(type -> type.getAttributeValueList()) + .flatMap(List::stream) + .collect(Collectors.toList()); + } + + @Transactional + public Boolean edit(EditProductDTO editProductDTO) { + TProduct tProduct = tProductMapper.selectById(editProductDTO.getId()); + Assert.notNull(tProduct, "Unknown Product!"); + //编辑商品标签,先删除再添加 + productLabelService.deleteByProductId(editProductDTO.getId()); + productLabelService.saveBatch( + resolveProductLabel(editProductDTO.getProductLabelInfo().stream().map(ProductLabelVO::getId).collect(Collectors.toList()) + , tProduct.getId(), editProductDTO.getTimeZone())); + //编辑商品库存,先删除再添加 +// tProductStockService.deleteByProductId(editProductDTO.getId()); +// tProductStockService.saveBatch(resolveProductStore(editProductDTO.getStoreInfoList(), tProduct.getId(), editProductDTO.getTimeZone())); + //编辑商品属性,先删除再添加 + tProductAttributeService.deleteByProductId(editProductDTO.getId()); + tProductAttributeService.saveBatch(resolveProductAttribute(editProductDTO.getAttributeItemInfo(), tProduct.getId(), editProductDTO.getTimeZone())); + //编辑商品搭配,先删除再添加 + tProductAssortmentService.deleteByProductId(editProductDTO.getId()); + if (!CollectionUtils.isEmpty(editProductDTO.getAssortmentList())) { + tProductAssortmentService.saveBatch(resolveProductAssortment(editProductDTO.getAssortmentList(), tProduct.getId(), editProductDTO.getTimeZone())); + } + //编辑商品 +// tProduct.setPictureUrl(editProductDTO.getPictureUrl()); +// tProduct.setPictureName(editProductDTO.getPictureName()); +// tProduct.setPrice(editProductDTO.getPrice()); +// tProduct.setMd5(editProductDTO.getMd5()); +// tProduct.setUpdateDate(DateUtil.getByTimeZone(editProductDTO.getTimeZone())); + //计算商品总数 +// Long count = editProductDTO.getStoreInfoList().stream() +// .map(v -> v.getStock().stream().filter(f -> Objects.nonNull(f.getNum())).mapToLong(BatchUploadProductStoreStockDTO::getNum).sum()) +// .collect(Collectors.collectingAndThen(Collectors.toList(), value -> value.stream().mapToLong(v2 -> v2).sum())); +// tProduct.setTotal(count.intValue()); + //编辑重新识别商品主色 +// List> rgbList = pythonService.colorExtract("color_extract",tProduct.getPictureUrl(),0); +// List> hsvList = pythonService.colorExtract("color_extract",tProduct.getPictureUrl(),1); +// if(!CollectionUtils.isEmpty(rgbList) && !CollectionUtils.isEmpty(rgbList.get(0)) && !CollectionUtils.isEmpty(hsvList) && !CollectionUtils.isEmpty(hsvList.get(0)) ){ +// List rgb = rgbList.get(0); +// tProduct.setRgb(String.join("_",rgb)); +// List hsv = hsvList.get(0); +// PantoneVO pantoneVO = panToneService.getByHSV(Integer.valueOf(hsv.get(0)),Integer.valueOf(hsv.get(1)),Integer.valueOf(hsv.get(2))); +// if(Objects.nonNull(pantoneVO)){ +// tProduct.setColor(pantoneVO.getTcx()); +// } +// } +// tProductMapper.updateById(tProduct); + + return Boolean.TRUE; + } + + private List resolveProductAttribute(AttributeVO attributeItemInfo, Long productId, String timeZone) { + List result = Lists.newArrayList(); + if (CollectionUtil.isEmpty(attributeItemInfo.getAttributeTypeList())) { + TProductAttribute tProductAttribute = new TProductAttribute(); + result.add(tProductAttribute); + + tProductAttribute.setCreateDate(DateUtil.getByTimeZone(timeZone)); + tProductAttribute.setProductId(productId); + tProductAttribute.setAttributeItem(attributeItemInfo.getLabelItem()); + tProductAttribute.setAttributeType(""); + tProductAttribute.setAttributeValue(""); + } else { + attributeItemInfo.getAttributeTypeList().forEach(type -> { + if (CollectionUtil.isEmpty(type.getAttributeValueList())) { + TProductAttribute tProductAttribute = new TProductAttribute(); + result.add(tProductAttribute); + + tProductAttribute.setCreateDate(DateUtil.getByTimeZone(timeZone)); + tProductAttribute.setProductId(productId); + tProductAttribute.setAttributeItem(attributeItemInfo.getLabelItem()); + tProductAttribute.setAttributeType(type.getLabelType() == null ? "" : type.getLabelType()); + tProductAttribute.setAttributeValue(""); + } else { + type.getAttributeValueList().forEach(value -> { + TProductAttribute tProductAttribute = new TProductAttribute(); + result.add(tProductAttribute); + + tProductAttribute.setCreateDate(DateUtil.getByTimeZone(timeZone)); + tProductAttribute.setProductId(productId); + tProductAttribute.setAttributeItem(attributeItemInfo.getLabelItem()); + tProductAttribute.setAttributeType(type.getLabelType() == null ? "" : type.getLabelType()); + tProductAttribute.setAttributeValue(value == null ? "" : value); + }); + } + }); + } + return result; + } + + private List resolveProductAssortment(List> assortmentList, Long productId, + String timeZone) { + List returnProductAssortmentList = Lists.newArrayList(); + for (int i = 0; i < assortmentList.size(); i++) { + List productAssortmentVOS = assortmentList.get(i); + for (ProductAssortmentVO productAssortmentVO : productAssortmentVOS) { + TProduct tProduct = tProductMapper.selectById(productAssortmentVO.getProductId()); + productAssortmentVO.setGeneratePictureUrl(tProduct.getPictureUrl()); + returnProductAssortmentList.add(TProductAssortment.builder() + .createDate(DateUtil.getByTimeZone(timeZone)) + .generatePictureUrl(productAssortmentVO.getGeneratePictureUrl()) + .coverSort(i+1) + .assortmentProductId(productAssortmentVO.getProductId()) + .productId(productId).build()); + } + } + return returnProductAssortmentList; + } + + @Transactional + public Boolean delete(StoreDeleteDTO deleteDTO) { + TProduct tProduct = tProductMapper.selectById(deleteDTO.getId()); + Assert.notNull(tProduct, "Unknown Product!"); + //删除商品库存 + tProductStockService.deleteByProductId(deleteDTO.getId()); + //删除商品标签 + productLabelService.deleteByProductId(deleteDTO.getId()); + //删除商品搭配 + tProductAssortmentService.deleteByProductId(deleteDTO.getId()); + //删除搭配对应的商品 + tProductAssortmentService.deleteByAssortmentProductId(deleteDTO.getId()); + //删除商品属性 + tProductAttributeService.deleteByProductId(deleteDTO.getId()); + //删除商品主体 + tProductMapper.deleteById(deleteDTO.getId()); + return Boolean.TRUE; + } + + /** + * 批量上传文件 + * + * @param files + * @param files + * @return + */ + @Transactional + public TProductBatchUploadVo batchUploadProduct(MultipartFile[] files, String timeZone) { + //用户信息 + AuthPrincipalVo userInfo = UserContext.getUserHolder(); + TProductBatchUploadVo result = new TProductBatchUploadVo(); + List productIds = Lists.newArrayList(); + result.setProductIds(productIds); + //分批上传文件 + Stream.of(files).forEach(file -> { + String path = calculateFileUrl(userInfo.getId()); + File fileNew = FileUtil.upload(file, path); +// String md5 = MD5Utils.encryptFile(file); + TProduct saveProduct = resolveData(userInfo, fileNew, null, timeZone, files.length); + this.save(saveProduct); + productIds.add(saveProduct.getId().toString()); + }); + return result; + } + + /** + * 上传文件-新增用 + * + * @param timeZone + * @param md5 + * @param file + * @return + */ + private final static String MI_TU_BUCKET_NAME = "mi-tu"; + @Transactional + public TProductSingleUploadVo singleUploadProduct(MultipartFile file, String md5, String timeZone) { + Long accountId = UserContext.getUserHolder().getId(); + //md5去重 + Assert.isTrue(!existsMd5(md5,null), "Product already exists!"); + //上传路径 + + // 根据mi-tu图片名获取item_code + String originalFilename = file.getOriginalFilename(); + if (originalFilename == null) { + throw new BusinessException("file name is null."); + } + String itemNameColorCode = originalFilename.substring(0, originalFilename.lastIndexOf('.')); + // 根据itemName查询mi-tu商品信息 + String[] split = itemNameColorCode.split("_"); + String itemName = split[0]; + String colorCode = split[1]; + List miTuProductList = getMiTuProductList(itemName, colorCode); + int total = 0; +// for (MiTuProduct miTuProduct : miTuProductList) { +// total = total + miTuProduct.getQtyOnHand(); +// } + if (CollectionUtils.isEmpty(miTuProductList)) { + throw new BusinessException("Mi-Tu Product not found."); + } + String minioPath = minioUtil.getMinioPath(accountId,miTuProductList.get(0).getItemGroup(), miTuProductList.get(0).getSubGroup(), originalFilename); + String minioFullPath = minioUtil.upload(MI_TU_BUCKET_NAME, minioPath, file); + TProduct saveProduct = new TProduct(); + saveProduct.setAccountId(accountId); + saveProduct.setPrice(BigDecimal.valueOf(miTuProductList.get(0).getPriceSales())); + saveProduct.setOnSaleState(1); + //上传中 + saveProduct.setUploadState(0); + saveProduct.setPictureUrl(minioFullPath); + saveProduct.setPictureName(itemNameColorCode); + saveProduct.setMd5(md5); + //按时区计算 + saveProduct.setCreateDate(DateUtil.getByTimeZone(timeZone)); + + saveProduct.setColor(colorCode); + // 根据当前已有店铺查询商品店铺库存 + List miTuProductStock = new ArrayList<>(); + List storeList = storeService.list(); + HashMap storeMap = new HashMap<>(); + for (TStore tStore : storeList) { + storeMap.put(tStore.getName(), tStore.getId()); + } + List storeNameList = storeList.stream().map(TStore::getName).collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(storeNameList)) { + miTuProductStock = getMiTuProductStock(miTuProductList.get(0).getPluCode(), miTuProductList.get(0).getColor()); + miTuProductStock = miTuProductStock.stream().filter(o -> storeNameList.contains(o.getWhCode())).collect(Collectors.toList()); + } + for (MiTuProductStock tuProductStock : miTuProductStock) { + total = total + tuProductStock.getNum(); + } + saveProduct.setTotal(total); + tProductMapper.insert(saveProduct); +// List productStockList = new ArrayList<>(); + HashMap> map = new HashMap<>(); + for (MiTuProductStock mituProductStock : miTuProductStock) { + if (map.containsKey(mituProductStock.getWhCode())) { + BatchUploadProductStoreStockDTO dto = new BatchUploadProductStoreStockDTO(); + dto.setSize(mituProductStock.getSize()); + dto.setNum(mituProductStock.getNum()); + map.get(mituProductStock.getWhCode()).add(dto); + }else { + List dtoList = new ArrayList<>(); + BatchUploadProductStoreStockDTO dto = new BatchUploadProductStoreStockDTO(); + dto.setSize(mituProductStock.getSize()); + dto.setNum(mituProductStock.getNum()); + dtoList.add(dto); + map.put(mituProductStock.getWhCode(), dtoList); + } + } + for (String whCode : map.keySet()) { + Long storeId = storeMap.get(whCode); + List batchUploadProductStoreStockDTOS = map.get(whCode); + String jsonString = JSON.toJSONString(batchUploadProductStoreStockDTOS); + TProductStock tProductStock = TProductStock.builder() + .productId(saveProduct.getId()) + .storeId(storeId) + .stockContent(jsonString) + .createDate(new Date()) + .build(); + tProductStockService.save(tProductStock); + } + for (MiTuProduct miTuProduct : miTuProductList) { + miTuProduct.setProductId(saveProduct.getId()); + miTuProductMapper.insert(miTuProduct); + } + return new TProductSingleUploadVo(saveProduct.getId().toString(), minioUtil.getPresignedUrl(minioFullPath, 24 * 60), itemNameColorCode, md5); + } + + private List getMiTuProductStock(String pluCode, String color) { + List miTuProductStockList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + // 注册 JDBC 驱动器 + Class.forName(JDBC_DRIVER); + + // 打开一个连接 + log.info("连接数据库..."); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + + // 执行查询 + log.info("创建声明..."); + stmt = conn.createStatement(); + String sql; + + // 构建完整的 SQL 查询语句 + sql = "SELECT\n" + + "WHCODE,\n" + + "SIZE,\n" + + "count(1) as num\n" + + "FROM v_MZG003A\n" + + "WHERE plu_code = '" + pluCode + "'\n" + + "AND COLOR = '" + color + "'\n" + + "GROUP BY WHCODE,SIZE\n" + + "ORDER BY WHCODE,SIZE"; + ResultSet rs = stmt.executeQuery(sql); + + // 处理结果集 + while (rs.next()) { + MiTuProductStock stock = new MiTuProductStock(); + // 根据结果集设置 MiTuProduct 的属性 + stock.setWhCode(rs.getString("WHCODE")); + stock.setSize(rs.getString("SIZE")); + stock.setNum(rs.getInt("num")); + // 添加到列表中 + miTuProductStockList.add(stock); + } + + // 清理环境 + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException se) { + // 处理 JDBC 错误 + se.printStackTrace(); + } catch (Exception e) { + // 处理 Class.forName 错误 + e.printStackTrace(); + } finally { + // 关闭资源 + try { + if (stmt != null) stmt.close(); + } catch (SQLException se2) { + se2.printStackTrace(); + } + try { + if (conn != null) conn.close(); + } catch (SQLException se) { + se.printStackTrace(); + } + } + System.out.println("mi-tu商品查询执行完成!"); + return miTuProductStockList; + } + + private List getMiTuProductList(String itemName, String colorCode) { + List miTuProductList = new ArrayList<>(); + Connection conn = null; + Statement stmt = null; + try { + // 注册 JDBC 驱动器 + Class.forName(JDBC_DRIVER); + + // 打开一个连接 + log.info("连接数据库..."); + conn = DriverManager.getConnection(DB_URL, USER, PASS); + + // 执行查询 + log.info("创建声明..."); + stmt = conn.createStatement(); + String sql; + + // 构建完整的 SQL 查询语句 + sql = "SELECT * FROM v_item_1A\n" + + "WHERE item_name = '" + itemName + "'\n" + + "AND Color = '" + colorCode + "'"; + ResultSet rs = stmt.executeQuery(sql); + + // 处理结果集 + while (rs.next()) { + MiTuProduct miTuProduct = new MiTuProduct(); + // 根据结果集设置 MiTuProduct 的属性 + miTuProduct.setPluCode(rs.getString("plu_code")); + miTuProduct.setItemCode(rs.getString("item_code")); + miTuProduct.setItemName(rs.getString("item_name")); + miTuProduct.setItemBarcode(rs.getString("item_barcode")); + miTuProduct.setUnit(rs.getString("unit")); + miTuProduct.setItemType(rs.getString("item_type")); + miTuProduct.setQtyOnHand(rs.getInt("qty_on_hand")); + miTuProduct.setQtyOnOrd(rs.getInt("qty_on_ord")); + miTuProduct.setPriceSales(rs.getDouble("price_sales")); + miTuProduct.setBrand(rs.getString("Brand")); + miTuProduct.setGender(rs.getString("Gender")); + miTuProduct.setYear(rs.getString("Year")); + miTuProduct.setSeason(rs.getString("Season")); + miTuProduct.setSampleNon(rs.getString("Sample/non")); + miTuProduct.setItemGroup(rs.getString("Item_group")); + miTuProduct.setSubGroup(rs.getString("Sub_gruop")); + miTuProduct.setCountry(rs.getString("Country")); + miTuProduct.setSupplier(rs.getString("Supplier")); + miTuProduct.setSize(rs.getString("Size")); + miTuProduct.setColor(rs.getString("Color")); + miTuProduct.setImage(rs.getString("Image")); + // 添加到列表中 + miTuProductList.add(miTuProduct); + } + + // 清理环境 + rs.close(); + stmt.close(); + conn.close(); + } catch (SQLException se) { + // 处理 JDBC 错误 + se.printStackTrace(); + } catch (Exception e) { + // 处理 Class.forName 错误 + e.printStackTrace(); + } finally { + // 关闭资源 + try { + if (stmt != null) stmt.close(); + } catch (SQLException se2) { + se2.printStackTrace(); + } + try { + if (conn != null) conn.close(); + } catch (SQLException se) { + se.printStackTrace(); + } + } + System.out.println("mi-tu商品查询执行完成!"); + return miTuProductList; + } + + private List resolveProductStore(List storeInfos, Long productId, String timeZone) { + List productStocks = Lists.newArrayList(); + storeInfos.forEach(productStoreDTO -> + productStocks.add(TProductStock.builder() + .createDate(DateUtil.getByTimeZone(timeZone)) + .storeId(Long.valueOf(productStoreDTO.getStoreId())) + .stockContent(JSON.toJSONString(productStoreDTO.getStock())) + .productId(productId) + .build()) + ); + return productStocks; + } + + private List resolveProductLabel(List labelIds, Long productId, String timeZone) { + List productLabels = Lists.newArrayList(); + labelIds.forEach(labelId -> { + productLabels.add(TProductLabel.builder() + .createDate(DateUtil.getByTimeZone(timeZone)) + .labelId(Long.valueOf(labelId)) + .productId(productId) + .build()); + }); + return productLabels; + } + + private String calculateFileUrl(Long userId) { + String rootPath = fileProperties.getSys().getPath(); + String day = DateUtil.dateToStr(new Date(), DateUtil.YYYYMM); + return rootPath + day + File.separator + "userFile" + File.separator + "product" + + File.separator + userId + File.separator + UUID.randomUUID().toString(); + } + + private TProduct resolveData(AuthPrincipalVo userInfo, + File file, String md5, String timeZone, Integer total) { + TProduct product = new TProduct(); + product.setAccountId(userInfo.getId()); + product.setOnSaleState(1); + product.setTotal(total); + //上传中 + product.setUploadState(0); + product.setPictureUrl(file.getAbsolutePath()); + String prefix = file.getName().substring(0, file.getName().lastIndexOf(".")); + product.setPictureName(prefix); + product.setMd5(md5); + //按时区计算 + product.setCreateDate(DateUtil.getByTimeZone(timeZone)); + String linuxDomain = fileProperties.getLinuxDomain(); + if (!StringUtils.isEmpty(linuxDomain)) { + //linux 系统 + String oldPath = fileProperties.getSys().getPath(); + product.setPictureUrl(file.getAbsolutePath().replace(oldPath, linuxDomain)); + } + return product; + } + + /** + * 批量上传文件后关联信息 + * + * @param product + * @return + */ +// @Transactional + @Resource + private MiTuProductMapper miTuProductMapper; + public TProductBatchUploadRelationVo batchUploadProductRelation(BatchUploadProductDTO product) { + //用户信息 + AuthPrincipalVo userInfo = UserContext.getUserHolder(); + Long accountId = userInfo.getId(); + //防止断线,预先清除 + LocalCacheUtils.delProductUploadProcessCache(accountId); + List tProducts = tProductMapper.selectBatchIds(product.getProductIds()); + Assert.notEmpty(tProducts, "Product does not exist !"); + Assert.isTrue(tProducts.size() <= 100, "A maximum of 100 images can be uploaded in a batch !"); + //防止前端重复传,过滤已添加的 + tProducts = tProducts.stream().filter(f -> f.getUploadState() == 0).collect(Collectors.toList()); + Assert.notEmpty(tProducts, "TProduct added !"); + Integer totalSize = tProducts.size(); +// for (TProduct tProduct : tProducts) { +// List miTuProductList = getMiTuProductList(tProduct.getPictureName()); +// if (!CollectionUtils.isEmpty(miTuProductList)) { +// MiTuProduct miTuProduct = miTuProductList.get(0); +// miTuProduct.setId(tProduct.getId()); +// miTuProductMapper.insert(miTuProduct); +// } +// } + + TProductBatchUploadRelationVo result = new TProductBatchUploadRelationVo(); + result.setAccountId(userInfo.getId()); + List uploadProductUrls = Lists.newArrayList(); + result.setPictureUrls(uploadProductUrls); + //计算商品总数 +// Long count = product.getStoreInfos().stream() +// .map(v -> v.getStock().stream().filter(f -> Objects.nonNull(f.getNum())).mapToLong(BatchUploadProductStoreStockDTO::getNum).sum()) +// .collect(Collectors.collectingAndThen(Collectors.toList(), value -> value.stream().mapToLong(v2 -> v2).sum())); + + //获取该用户所有店铺下所有商品 + //查询用户店铺 + List storeVOS = storeService.queryUserStore(null, null); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + List dataBase = CollectionUtil.isEmpty(productIds)? Lists.newArrayList() :getUseProductNum(productIds); + + Map> productIdToMap = Maps.newHashMap(); + //识别进度开始 + setAttributeProcess(accountId, totalSize, 0, Boolean.FALSE, Boolean.TRUE); + tProducts.forEach(tProduct -> { + try { + //计算python商品属性,性能慢 一次一件 + JSONObject productIdInnerToMap = pythonService.attributeRecognition( + Collections.singletonList(tProduct.getPictureUrl()), + Collections.singletonList(tProduct.getId().toString())); + //保存商品属性 + tProductAttributeService.saveBatch(resolveProductAttributeNew(productIdInnerToMap, product.getTimeZone())); +// resolveProductIdToMap(productIdToMap, productIdInnerToMap); + //更新商品的搭配状态为未搭配 +// tProduct.setCollocationState(0); +// this.updateById(tProduct); + } catch (Exception e) { + log.info("用户##{}###商品识别异常###{}", userInfo.getUsername(), ExceptionUtil.stacktraceToString(e)); + } +// try { +// //识别商品主色 +// List> rgbList = pythonService.colorExtract("color_extract",tProduct.getPictureUrl(),0); +// List> hsvList = pythonService.colorExtract("color_extract",tProduct.getPictureUrl(),1); +// if(CollectionUtils.isEmpty(rgbList) || CollectionUtils.isEmpty(rgbList.get(0)) +// || CollectionUtils.isEmpty(hsvList) || CollectionUtils.isEmpty(hsvList.get(0)) ){ +// return; +// } +// List rgb = rgbList.get(0); +// tProduct.setRgb(String.join("_",rgb)); +// List hsv = hsvList.get(0); +// PantoneVO pantoneVO = panToneService.getByHSV(Integer.valueOf(hsv.get(0)),Integer.valueOf(hsv.get(1)),Integer.valueOf(hsv.get(2))); +// if(Objects.nonNull(pantoneVO)){ +// tProduct.setColor(pantoneVO.getTcx()); +// } +// } catch (Exception e) { +// log.info("用户##{}###商品识别商品主色识别###{}", userInfo.getUsername(), ExceptionUtil.stacktraceToString(e)); +// } + //统计进度 + setAttributeProcess(accountId, totalSize, 1, Boolean.FALSE, Boolean.FALSE); + }); + //统计属性进度为1 + setAttributeProcess(accountId, null, null, Boolean.TRUE, Boolean.FALSE); + + //计算 +// if(count >0){ +// dataBase.addAll(tProducts); +// } + dataBase.addAll(tProducts); + Map tProductIdToAttributeItemNewMap = CollectionUtil.isEmpty(dataBase) ? Maps.newHashMap() + : tProductAttributeService.findByProductAttributesItem(dataBase.stream().map(TProduct::getId).collect(Collectors.toList())); + //去重 + List dataBaseAfter = CollectionUtil.emptyIfNull(dataBase).stream().collect(Collectors.collectingAndThen( + Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TProduct::getId))), ArrayList::new)); + List dataBaseAfterNew = CollectionUtil.emptyIfNull(dataBaseAfter).stream() + .filter(f-> !StringUtils.isEmpty(tProductIdToAttributeItemNewMap.get(f.getId()))).collect(Collectors.toList()); + //调用python 搭配出标签属性,一次10套 + List> questList = Lists.partition(tProducts, 10); + //搭配进度开始 + setCollocationProcess(accountId, totalSize, null, Boolean.FALSE, Boolean.TRUE); + questList.forEach(list -> { + //校验规则 +// List validateList = validateGenerateProductAssortment(list, productIdToMap, dataBaseAfterNew, tProductIdToAttributeItemNewMap); + List validateList = list; + if (CollectionUtils.isEmpty(validateList)) { + //统计进度 + setCollocationProcess(accountId, totalSize, list.size(), Boolean.FALSE, Boolean.FALSE); + return; + } + try { +// Map dataBaseMap = dataBaseAfterNew.stream().collect(Collectors.toMap(p -> p.getId().toString(), +// p2 -> GenerateCollocationDataBaseDTO +// .builder() +// .category(tProductIdToAttributeItemNewMap.get(p2.getId())) +// .path(p2.getPictureUrl()).build(), (v1, v2) -> v2)); + //推荐搭配 +// List collocationOutResult = pythonService.generateCollocation( +// validateList.stream() +// .map(product1 -> +// GenerateCollocationQueryDTO.builder() +// .item_category(productIdToMap.get(product1.getId().toString()).get("Item").toString()) +// .path(product1.getPictureUrl()) +// .item_id(product1.getId().toString()).build()) +// .collect(Collectors.toList()), dataBaseMap +// ); + QueryWrapper qw = new QueryWrapper<>(); +// qw.lambda().notIn(TProduct::getId, validateList.stream().map(TProduct::getId).collect(Collectors.toList())); + List db = tProductMapper.selectList(qw); + List query = new ArrayList<>(); + List database = new ArrayList<>(); + for (TProduct tProduct : validateList) { + GenerateCollocationQueryNewDTO vo = new GenerateCollocationQueryNewDTO(); + vo.setItem_name(tProduct.getPictureName().split("_")[0]); + vo.setImage_path(tProduct.getPictureUrl()); + String[] split = tProduct.getPictureUrl().split("/"); + vo.setSemantic_category(split[2] + "/" + split[3]); + query.add(vo); + } + for (TProduct tProduct : db) { + GenerateCollocationQueryNewDTO vo = new GenerateCollocationQueryNewDTO(); + vo.setItem_name(tProduct.getPictureName().split("_")[0]); + vo.setImage_path(tProduct.getPictureUrl()); + String[] split = tProduct.getPictureUrl().split("/"); + vo.setSemantic_category(split[2] + "/" + split[3]); + database.add(vo); + } + List collocationOutResult = pythonService.generateCollocationNew(query, database); + //保存搭配数据 + tProductAssortmentService.saveBatch( + resolveProductAssortmentNew(collocationOutResult, product.getTimeZone())); + //更新商品的搭配状态为已搭配 + System.out.println(collocationOutResult); + validateList.stream().forEach(pro -> pro.setCollocationState(1)); + this.updateBatchById(validateList); + } catch (Exception e) { + log.info("用户##{}###商品搭配异常###{}", userInfo.getUsername(), ExceptionUtil.stacktraceToString(e)); + } + //统计进度 + setCollocationProcess(accountId, totalSize, list.size(), Boolean.FALSE, Boolean.FALSE); + }); + //统计搭配进度为1 + setCollocationProcess(accountId, null, null, Boolean.TRUE, Boolean.FALSE); + tProducts.forEach(p -> { + p.setUploadState(1); +// p.setTotal(count.intValue()); +// p.setPrice(product.getPrice()); + }); + //分批上传文件 + tProducts.forEach(product1 -> { + uploadProductUrls.add(product1.getPictureUrl()); + //保存商品标签关系 + productLabelService.saveBatch(resolveProductLabel(product.getLabelIds(), product1.getId(), product.getTimeZone())); + //保存商品库存 +// tProductStockService.saveBatch(resolveProductStore(product.getStoreInfos(), product1.getId(), product.getTimeZone())); + }); + //更新商品状态 + this.updateBatchById(tProducts); + return result; + } + + private Collection resolveProductAssortmentNew(List collocationOutResult, String timeZone) { + log.info("获取python推荐搭配总数据是###{}", JSON.toJSONString(collocationOutResult)); + List result = Lists.newArrayList(); + collocationOutResult.forEach(collocation -> { + + for (int i = 0; i < collocation.getOutfits().size(); i++) { + List generateCollocationQueryNewDTOS = collocation.getOutfits().get(i); + String url = generateCollocationQueryNewDTOS.get(0).getImage_path(); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(TProduct::getPictureUrl, url); + TProduct tProduct = tProductMapper.selectList(qw).get(0); + for (int j = 0; j < generateCollocationQueryNewDTOS.size(); j++) { + if (j == 0) { + TProductAssortment tProductAssortment = TProductAssortment.builder() + .createDate(DateUtil.getByTimeZone(timeZone)) + .generatePictureUrl(tProduct.getPictureUrl()) + .coverSort(i + 1) + .assortmentProductId(tProduct.getId()) + .productId(tProduct.getId()).build(); + result.add(tProductAssortment); + }else { + String assortmentUrl= generateCollocationQueryNewDTOS.get(j).getImage_path(); + QueryWrapper assortmentQw = new QueryWrapper<>(); + assortmentQw.lambda().like(TProduct::getPictureUrl, assortmentUrl); + TProduct assortmentProduct = tProductMapper.selectList(assortmentQw).get(0); + TProductAssortment tProductAssortment = TProductAssortment.builder() + .createDate(DateUtil.getByTimeZone(timeZone)) + .generatePictureUrl(assortmentProduct.getPictureUrl()) + .coverSort(i + 1) + .assortmentProductId(assortmentProduct.getId()) + .productId(tProduct.getId()).build(); + result.add(tProductAssortment); + } + } + } + }); + return result; + } + + public TProductBatchUploadRelationVo batchUploadProductRelationOriginal(BatchUploadProductDTO product) { + //用户信息 + AuthPrincipalVo userInfo = UserContext.getUserHolder(); + Long accountId = userInfo.getId(); + //防止断线,预先清除 + LocalCacheUtils.delProductUploadProcessCache(accountId); + List tProducts = tProductMapper.selectBatchIds(product.getProductIds()); + Assert.notEmpty(tProducts, "Product does not exist !"); + Assert.isTrue(tProducts.size() <= 100, "A maximum of 100 images can be uploaded in a batch !"); + //防止前端重复传,过滤已添加的 + tProducts = tProducts.stream().filter(f -> f.getUploadState() == 0).collect(Collectors.toList()); + Assert.notEmpty(tProducts, "TProduct added !"); + Integer totalSize = tProducts.size(); + + TProductBatchUploadRelationVo result = new TProductBatchUploadRelationVo(); + result.setAccountId(userInfo.getId()); + List uploadProductUrls = Lists.newArrayList(); + result.setPictureUrls(uploadProductUrls); + //计算商品总数 +// Long count = product.getStoreInfos().stream() +// .map(v -> v.getStock().stream().filter(f -> Objects.nonNull(f.getNum())).mapToLong(BatchUploadProductStoreStockDTO::getNum).sum()) +// .collect(Collectors.collectingAndThen(Collectors.toList(), value -> value.stream().mapToLong(v2 -> v2).sum())); + + //获取该用户所有店铺下所有商品 + //查询用户店铺 + List storeVOS = storeService.queryUserStore(null, null); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + List dataBase = CollectionUtil.isEmpty(productIds)? Lists.newArrayList() :getUseProductNum(productIds); + + Map> productIdToMap = Maps.newHashMap(); + //识别进度开始 + setAttributeProcess(accountId, totalSize, 0, Boolean.FALSE, Boolean.TRUE); + tProducts.forEach(tProduct -> { +// try { +// //计算python商品属性,性能慢 一次一件 +// Map> productIdInnerToMap = pythonService.attributeRecognition( +// Collections.singletonList(tProduct.getPictureUrl()), +// Collections.singletonList(tProduct.getId().toString())); +// //保存商品属性 +// tProductAttributeService.saveBatch(resolveProductAttribute(productIdInnerToMap, product.getTimeZone())); +// resolveProductIdToMap(productIdToMap, productIdInnerToMap); +// //更新商品的搭配状态为未搭配 +// tProduct.setCollocationState(0); +// this.updateById(tProduct); +// } catch (Exception e) { +// log.info("用户##{}###商品识别异常###{}", userInfo.getUsername(), ExceptionUtil.stacktraceToString(e)); +// } +// try { +// //识别商品主色 +// List> rgbList = pythonService.colorExtract("color_extract",tProduct.getPictureUrl(),0); +// List> hsvList = pythonService.colorExtract("color_extract",tProduct.getPictureUrl(),1); +// if(CollectionUtils.isEmpty(rgbList) || CollectionUtils.isEmpty(rgbList.get(0)) +// || CollectionUtils.isEmpty(hsvList) || CollectionUtils.isEmpty(hsvList.get(0)) ){ +// return; +// } +// List rgb = rgbList.get(0); +// tProduct.setRgb(String.join("_",rgb)); +// List hsv = hsvList.get(0); +// PantoneVO pantoneVO = panToneService.getByHSV(Integer.valueOf(hsv.get(0)),Integer.valueOf(hsv.get(1)),Integer.valueOf(hsv.get(2))); +// if(Objects.nonNull(pantoneVO)){ +// tProduct.setColor(pantoneVO.getTcx()); +// } +// } catch (Exception e) { +// log.info("用户##{}###商品识别商品主色识别###{}", userInfo.getUsername(), ExceptionUtil.stacktraceToString(e)); +// } + //统计进度 + setAttributeProcess(accountId, totalSize, 1, Boolean.FALSE, Boolean.FALSE); + }); + //统计属性进度为1 + setAttributeProcess(accountId, null, null, Boolean.TRUE, Boolean.FALSE); + + //计算 +// if(count >0){ +// dataBase.addAll(tProducts); +// } + dataBase.addAll(tProducts); + Map tProductIdToAttributeItemNewMap = CollectionUtil.isEmpty(dataBase) ? Maps.newHashMap() + : tProductAttributeService.findByProductAttributesItem(dataBase.stream().map(TProduct::getId).collect(Collectors.toList())); + //去重 + List dataBaseAfter = CollectionUtil.emptyIfNull(dataBase).stream().collect(Collectors.collectingAndThen( + Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TProduct::getId))), ArrayList::new)); + List dataBaseAfterNew = CollectionUtil.emptyIfNull(dataBaseAfter).stream() + .filter(f-> !StringUtils.isEmpty(tProductIdToAttributeItemNewMap.get(f.getId()))).collect(Collectors.toList()); + //调用python 搭配出标签属性,一次10套 + List> questList = Lists.partition(tProducts, 10); + //搭配进度开始 + setCollocationProcess(accountId, totalSize, null, Boolean.FALSE, Boolean.TRUE); + questList.forEach(list -> { + //校验规则 + List validateList = validateGenerateProductAssortment(list, productIdToMap, dataBaseAfterNew, tProductIdToAttributeItemNewMap); + if (CollectionUtils.isEmpty(validateList)) { + //统计进度 + setCollocationProcess(accountId, totalSize, list.size(), Boolean.FALSE, Boolean.FALSE); + return; + } + try { + Map dataBaseMap = dataBaseAfterNew.stream().collect(Collectors.toMap(p -> p.getId().toString(), + p2 -> GenerateCollocationDataBaseDTO + .builder() + .category(tProductIdToAttributeItemNewMap.get(p2.getId())) + .path(p2.getPictureUrl()).build(), (v1, v2) -> v2)); + //推荐搭配 + List collocationOutResult = pythonService.generateCollocation( + validateList.stream() + .map(product1 -> + GenerateCollocationQueryDTO.builder() + .item_category(productIdToMap.get(product1.getId().toString()).get("Item").toString()) + .path(product1.getPictureUrl()) + .item_id(product1.getId().toString()).build()) + .collect(Collectors.toList()), dataBaseMap + ); + //保存搭配数据 + tProductAssortmentService.saveBatch( + resolveProductAssortment(collocationOutResult, dataBaseMap, product.getTimeZone())); + //更新商品的搭配状态为已搭配 + validateList.stream().forEach(pro -> pro.setCollocationState(1)); + this.updateBatchById(validateList); + } catch (Exception e) { + log.info("用户##{}###商品搭配异常###{}", userInfo.getUsername(), ExceptionUtil.stacktraceToString(e)); + } + //统计进度 + setCollocationProcess(accountId, totalSize, list.size(), Boolean.FALSE, Boolean.FALSE); + }); + //统计搭配进度为1 + setCollocationProcess(accountId, null, null, Boolean.TRUE, Boolean.FALSE); + tProducts.forEach(p -> { + p.setUploadState(1); +// p.setTotal(count.intValue()); +// p.setPrice(product.getPrice()); + }); + //分批上传文件 + tProducts.forEach(product1 -> { + uploadProductUrls.add(product1.getPictureUrl()); + //保存商品标签关系 + productLabelService.saveBatch(resolveProductLabel(product.getLabelIds(), product1.getId(), product.getTimeZone())); + //保存商品库存 +// tProductStockService.saveBatch(resolveProductStore(product.getStoreInfos(), product1.getId(), product.getTimeZone())); + }); + //更新商品状态 + this.updateBatchById(tProducts); + return result; +} + + public List getUseProductNum(List productIds ){ + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("id",productIds); + queryWrapper.gt("total",0); + List products = tProductMapper.selectList(queryWrapper); + return null == products ? Lists.newArrayList() : products; + } + + private void resolveProductIdToMap(Map> productIdToMap, + Map> productIdInnerToMap) { + if (MapUtil.isEmpty(productIdInnerToMap)) { + return; + } + productIdInnerToMap.forEach((k, v) -> { + productIdToMap.put(k, v); + }); + } + + private List validateGenerateProductAssortment(List list, Map> productIdToMap, + List dataBase, Map tProductIdToAttributeItemMap) { + //1.如果输入top: + //首先判断outer数量是否是0,如果是0,则pos即bottom的数量,否则pos是bottom的数量乘以outer的数量。 + //2.如果输入bottom: + //首先判断outer数量是否是0,如果是0,则pos即top的数量,否则pos是top的数量乘以outer的数量。 + //3.如果输入outer: 则pos等于top的数量乘以bottom的数量,加上jumpsuit的数量,再加上dress的数量。 + //4.如果输入dress或者jumpsuit:则pos即outer的数量。 + //因此java端的校验是,先根据这个逻辑计算出pos,然后比较pos和topk的关系,如果pos returnProductList = Lists.newArrayList(); + list.forEach(product -> { + List outerFilterList = dataBase.stream() + .filter(product1 -> "outer".equals(tProductIdToAttributeItemMap.get(product1.getId()))) + .collect(Collectors.toList()); + String item = CollectionUtil.isEmpty(productIdToMap) ? + tProductIdToAttributeItemMap.get(product.getId()) : productIdToMap.get(product.getId().toString()).get("Item").toString(); + if ("top".equals(item)) { + List bottomFilterList = dataBase.stream() + .filter(product1 -> "bottom".equals(tProductIdToAttributeItemMap.get(product1.getId()))) + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(outerFilterList)) { + if ((CollectionUtil.isNotEmpty(bottomFilterList) && bottomFilterList.size() >= 5)) { + returnProductList.add(product); + } + } else { + if ((CollectionUtil.isNotEmpty(bottomFilterList) + && (bottomFilterList.size() * outerFilterList.size()) >= 5)) { + returnProductList.add(product); + } + } + } else if ("bottom".equals(item)) { + List topFilterList = dataBase.stream() + .filter(product1 -> "top".equals(tProductIdToAttributeItemMap.get(product1.getId()))) + .collect(Collectors.toList()); + if (CollectionUtil.isEmpty(outerFilterList)) { + if ((CollectionUtil.isNotEmpty(topFilterList) && topFilterList.size() >= 5)) { + returnProductList.add(product); + } + } else { + if ((CollectionUtil.isNotEmpty(topFilterList) + && (topFilterList.size() * outerFilterList.size()) >= 5)) { + returnProductList.add(product); + } + } + } else if ("dress".equals(item) || "jumpsuit".equals(item)) { + if ((CollectionUtil.isNotEmpty(outerFilterList) && outerFilterList.size() >= 5)) { + returnProductList.add(product); + } + } else if ("outer".equals(item)) { + List topFilterList = dataBase.stream() + .filter(product1 -> "top".equals(tProductIdToAttributeItemMap.get(product1.getId()))) + .collect(Collectors.toList()); + List bottomFilterList = dataBase.stream() + .filter(product1 -> "bottom".equals(tProductIdToAttributeItemMap.get(product1.getId()))) + .collect(Collectors.toList()); + List jumpsuitFilterList = dataBase.stream() + .filter(product1 -> "jumpsuit".equals(tProductIdToAttributeItemMap.get(product1.getId()))) + .collect(Collectors.toList()); + List dressFilterList = dataBase.stream() + .filter(product1 -> "dress".equals(tProductIdToAttributeItemMap.get(product1.getId()))) + .collect(Collectors.toList()); + int value = getSize(topFilterList) * getSize(bottomFilterList) + getSize(jumpsuitFilterList) + getSize(dressFilterList); + if (value >= 5) { + returnProductList.add(product); + } + } + }); + return returnProductList; + + } + + private int getSize(List list) { + return list == null ? 0 : list.size(); + } + + /** + * 统计属性进度 + * + * @param userId + * @param total + * @param upload + * @param isEnd + */ + private void setAttributeProcess(Long userId, Integer total, Integer upload, Boolean isEnd, Boolean isStart) { + ProductProcessDTO productProcess = LocalCacheUtils.getProductUploadProcessCache(userId); + if (isEnd && productProcess.getTotal() == 0) { + //被删掉 + return; + } + if (productProcess.getTotal() == 0) { + productProcess.setTotal(total); + productProcess.setHasUpload(upload); + productProcess.setUploadType("Attribute"); + productProcess.setStatus(0); + } else if (isEnd) { + //没有被删掉 + productProcess.setHasUpload(productProcess.getTotal()); + productProcess.setStatus(0); + } else if (isStart) { + productProcess.setTotal(total); + productProcess.setHasUpload(0); + productProcess.setUploadType("Attribute"); + productProcess.setStatus(0); + } else { + productProcess.setHasUpload(productProcess.getHasUpload() + upload); + productProcess.setStatus(0); + } + LocalCacheUtils.setProductUploadProcessCache(userId, productProcess); + } + + /** + * 统计搭配进度 + * + * @param userId + * @param total + * @param upload + * @param isEnd + */ + private void setCollocationProcess(Long userId, Integer total, Integer upload, Boolean isEnd, Boolean isStart) { + ProductProcessDTO productProcess = LocalCacheUtils.getProductUploadProcessCache(userId); + if (isEnd && productProcess.getTotal() == 0) { + //被删掉 + return; + } + if (productProcess.getTotal() == 0) { + productProcess.setTotal(total); + productProcess.setHasUpload(upload); + productProcess.setUploadType("Collocation"); + productProcess.setStatus(0); + } else if (isEnd) { + //没有被删掉 + productProcess.setHasUpload(productProcess.getTotal()); + productProcess.setUploadType("Collocation"); + productProcess.setStatus(1); + } else if (isStart) { + productProcess.setTotal(total); + productProcess.setHasUpload(0); + productProcess.setUploadType("Collocation"); + productProcess.setStatus(0); + } else { + productProcess.setHasUpload(productProcess.getHasUpload() + upload); + productProcess.setUploadType("Collocation"); + if (productProcess.getHasUpload().equals(productProcess.getTotal())) { + productProcess.setStatus(1); + } + } + LocalCacheUtils.setProductUploadProcessCache(userId, productProcess); + } + + public static List resolveProductAttribute(Map> productIdToMap, String timeZone) { + List result = Lists.newArrayList(); + productIdToMap.forEach((k, v) -> { + String item = v.get("Item").toString(); + List objects = v.values().stream().collect(Collectors.toList()); + if (objects.size() == 1) { + //只识别一级标签时 + TProductAttribute tProductAttribute = new TProductAttribute(); + result.add(tProductAttribute); + +// tProductAttribute.setCreateDate(DateUtil.getByTimeZone(timeZone)); + tProductAttribute.setProductId(Long.valueOf(k)); + tProductAttribute.setAttributeItem(item); + tProductAttribute.setAttributeType(""); + tProductAttribute.setAttributeValue(""); + } else { + //包含二三级级标签时 + v.forEach((k1, v1) -> { + if ("Item".equals(k1)) { + return; + } + List attributeValueList = JSON.parseArray(v1.toString(), String.class); + attributeValueList.forEach(value -> { + TProductAttribute tProductAttribute = new TProductAttribute(); + result.add(tProductAttribute); + + tProductAttribute.setCreateDate(DateUtil.getByTimeZone(timeZone)); + tProductAttribute.setProductId(Long.valueOf(k)); + tProductAttribute.setAttributeItem(item); + tProductAttribute.setAttributeType(k1); + tProductAttribute.setAttributeValue(value); + }); + }); + } + + }); + return result; + } + + public static List resolveProductAttributeNew(JSONObject productIdToMap, String timeZone) { + List result = Lists.newArrayList(); + JSONObject data = productIdToMap.getJSONObject("data"); + data.forEach((k,v) -> { + JSONObject attributes = data.getJSONObject(k); + String item = attributes.getString("Item"); + attributes.forEach((k1,v1) -> { + if (!k1.equals("Item")) { + TProductAttribute tProductAttribute = new TProductAttribute(); + tProductAttribute.setProductId(Long.valueOf(k)); + tProductAttribute.setAttributeType(k1); + JSONArray attributesArray = attributes.getJSONArray(k1); + if (attributesArray.size() > 0) { + tProductAttribute.setAttributeValue(attributesArray.getString(0)); + tProductAttribute.setAttributeItem(item); + tProductAttribute.setCreateDate(DateUtil.getByTimeZone(timeZone)); + result.add(tProductAttribute); + } + } + }); + }); + return result; +// productIdToMap.getJSONObject("data").forEach((k, v) -> { +// String item = v.get("Item").toString(); +// List objects = v.values().stream().collect(Collectors.toList()); +// if (objects.size() == 1) { +// //只识别一级标签时 +// TProductAttribute tProductAttribute = new TProductAttribute(); +// result.add(tProductAttribute); +// +//// tProductAttribute.setCreateDate(DateUtil.getByTimeZone(timeZone)); +// tProductAttribute.setProductId(Long.valueOf(k)); +// tProductAttribute.setAttributeItem(item); +// tProductAttribute.setAttributeType(""); +// tProductAttribute.setAttributeValue(""); +// } else { +// //包含二三级级标签时 +// v.forEach((k1, v1) -> { +// if ("Item".equals(k1)) { +// return; +// } +// List attributeValueList = JSON.parseArray(v1.toString(), String.class); +// attributeValueList.forEach(value -> { +// TProductAttribute tProductAttribute = new TProductAttribute(); +// result.add(tProductAttribute); +// +// tProductAttribute.setCreateDate(DateUtil.getByTimeZone(timeZone)); +// tProductAttribute.setProductId(Long.valueOf(k)); +// tProductAttribute.setAttributeItem(item); +// tProductAttribute.setAttributeType(k1); +// tProductAttribute.setAttributeValue(value); +// }); +// }); +// } + +// }); + } + + private List resolveProductAssortment(List collocationOutResult, + Map dataBaseMap, + String timeZone) { + log.info("获取python推荐搭配总数据是###{}", com.alibaba.fastjson.JSON.toJSONString(dataBaseMap)); + List result = Lists.newArrayList(); +// collocationOutResult.forEach(collocation -> { +// //一套 +// AtomicReference coverSort = new AtomicReference<>(1); +// collocation.getOutput().forEach(out -> { +// out.forEach(outNner -> { +// result.add(TProductAssortment.builder() +// .createDate(DateUtil.getByTimeZone(timeZone)) +// .generatePictureUrl(dataBaseMap.get(outNner).getPath()) +// .coverSort(coverSort.get()) +// .assortmentProductId(Long.valueOf(outNner)) +// .productId(Long.valueOf(collocation.getQuery())).build()); +// }); +// coverSort.getAndSet(coverSort.get() + 1); +// }); +// }); + return result; + } + + /** + * 分页查询商品搭配 + * + * @param query + * @returnN + */ + public PageBaseResponse queryProductAssortmentPage(QueryProductAssortmentPageDTO query) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!org.springframework.util.StringUtils.isEmpty(query.getLabelItem())) { + List productIds = tProductAttributeService.findByItemAndType(query.getLabelItem(), query.getLabelTypeMap()); + if (CollectionUtils.isEmpty(productIds)) { + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIds); + } + if (!org.springframework.util.StringUtils.isEmpty(query.getAssortmentIdList())) { + List assortments = tProductAssortmentService.findByIds(query.getAssortmentIdList()); + if (!CollectionUtils.isEmpty(assortments)) { + List productIds = assortments.stream().map(TProductAssortment::getAssortmentProductId).collect(Collectors.toList()); + queryWrapper.notIn("id", productIds); + + } + } + //查询用户店铺 + List storeVOS = storeService.queryUserStore(null, null); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + if (CollectionUtils.isEmpty(productIds)) { + return PageBaseResponse.success(new Page<>()); + } + queryWrapper.in("id", productIds); + //上传成功的 + queryWrapper.eq("upload_state", 1); + queryWrapper.gt("total",0); + queryWrapper.orderByDesc("id"); + IPage page = getBaseMapper().selectPage( + new Page<>(query.getPage(), query.getSize()), queryWrapper); + if (CollectionUtils.isEmpty(page.getRecords())) { + return PageBaseResponse.success(new Page<>()); + } + IPage convert = page.convert((Function) + product -> + { + ProductAssortmentInnerVO result = CopyUtil.copyObject(product, ProductAssortmentInnerVO.class); + result.setProductId(product.getId().toString()); + result.setPictureUrl(minioUtil.getPresignedUrl(result.getPictureUrl(), 24 * 60)); + return result; + }); + return PageBaseResponse.success(convert); + } + + public List findByAccountId(Long accountId) { + QueryWrapper query = new QueryWrapper<>(); + query.eq("account_id", accountId); + query.eq("upload_state", 1); + return tProductMapper.selectList(query); + } + + private Boolean existsMd5(String md5,Long currentProductId) { + //查询用户店铺内商品是否重复 +// List storeVOS = storeService.queryUserStore(null, null); +// List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + QueryWrapper query = new QueryWrapper<>(); + query.eq("md5", md5); + if(Objects.nonNull(currentProductId)){ + //编辑时候不检验当前的商品 + return false; +// productIds.remove(currentProductId); + } +// if(!CollectionUtil.isEmpty(productIds)){ +// query.in("id", productIds); +// } +// query.eq("upload_state", 1); + return tProductMapper.exists(query); + } + + public TProductUploadVo upload(MultipartFile file,String md5, String timeZone,String id) { + TProduct tProduct = tProductMapper.selectById(id); + Assert.notNull(tProduct, "Unknown Product!"); + //md5去重 + Assert.isTrue(!existsMd5(md5,Long.valueOf(id)), "Product already exists!"); + String path = calculateFileUrl(UserContext.getUserHolder().getId()); + File fileNew = FileUtil.upload(file, path); + String url = fileNew.getAbsolutePath(); + String linuxDomain = fileProperties.getLinuxDomain(); + if (!StringUtils.isEmpty(linuxDomain)) { + //linux 系统 + String oldPath = fileProperties.getSys().getPath(); + url = url.replace(oldPath, linuxDomain); + } + String prefix = fileNew.getName().substring(0, fileNew.getName().lastIndexOf(".")); + return new TProductUploadVo(url, prefix,md5); + } + + + public ProductProcessDTO countProductUpdateProcess() { + AuthPrincipalVo userInfo = UserContext.getUserHolder(); + ProductProcessDTO process = LocalCacheUtils.getProductUploadProcessCache(userInfo.getId()); + if (ObjectUtils.isEmpty(process) || process.getTotal() == 0 || process.getHasUpload() == 0) { + process.setProcess(BigDecimal.ZERO); + return process; + } + int totalProcess = process.getTotal(); + BigDecimal result = BigDecimal.valueOf(process.getHasUpload()) + .divide(BigDecimal.valueOf(totalProcess), 3, BigDecimal.ROUND_CEILING); + if (result.compareTo(BigDecimal.ONE) == 0) { + LocalCacheUtils.delProductUploadProcessCache(userInfo.getId()); + } + process.setProcess(result); + log.info("商品上传统计进度###totalProcess###{}###hasUpload##{}", totalProcess, process.getHasUpload()); + return process; + } + + + /** + * 查询所有上架商品总数 + * + * @return + */ + private Long totalOnSale() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("on_sale_state", 1); + queryWrapper.eq("upload_state", 1); + return tProductMapper.selectCount(queryWrapper); + } + + public CountWorkBentchVO countWorkBench(String storeId) { + //角色信息 + RoleVO roleVO = roleService.queryUsrPermission(); + //用户信息 + AuthPrincipalVo info = UserContext.getUserHolder(); + //店铺信息 + List storeVO = storeService.queryUserStore(storeId, null); + return CountWorkBentchVO.builder().onSaleProductCount(totalOnSale().toString()) + .orderSuccessCount("0") + .storeCount(storeService.total().toString()) + .roleName(roleVO.getName()) + .userName(info.getUsername()) + .storeName(storeVO.get(0).getName()) + .storeAddress(storeVO.get(0).getAddress()) + .build(); + } + + @Transactional + public Boolean enableAccount(ProductOnSaleDTO productOnSaleDTO) { + TProduct product = tProductMapper.selectById(productOnSaleDTO.getId()); + Assert.notNull(product, "Unknown Product!"); + product.setOnSaleState(productOnSaleDTO.getOnSaleState()); + tProductMapper.updateById(product); + return Boolean.TRUE; + } + + public void reCollocationTask() { + //查询所有用户 + List accounts = accountService.queryAll(); + if (CollectionUtil.isEmpty(accounts)) { + return; + } + accounts.forEach(account -> reCollocationTaskByUserId(account.getId())); + } + + private void reCollocationTaskByUserId(Long userId) { + // 分页数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("upload_state", 1); + queryWrapper.eq("collocation_state", 0); + queryWrapper.eq("account_id", userId); + queryWrapper.orderByDesc("id"); + + //查询用户店铺 + List storeVOS = storeService.queryUserStoreByUserId(userId); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + List dataBase = CollectionUtil.isEmpty(productIds)? Lists.newArrayList() :tProductMapper.selectBatchIds(productIds); + Map tProductIdToAttributeItemNewMap = CollectionUtil.isEmpty(dataBase) ? Maps.newHashMap() + : tProductAttributeService.findByProductAttributesItem(dataBase.stream().map(TProduct::getId).collect(Collectors.toList())); + for (int i = 1; i < 10000; i++) { + IPage page = getBaseMapper().selectPage( + new Page<>(i, 200), queryWrapper); + if (CollectionUtils.isEmpty(page.getRecords())) { + break; + } + //调用python 搭配出标签属性,一次10套 + List> questList = Lists.partition(page.getRecords(), 10); + questList.forEach(list -> { + //校验规则 + List validateList = validateGenerateProductAssortment(list, null, dataBase, tProductIdToAttributeItemNewMap); + if (CollectionUtils.isEmpty(validateList)) { + return; + } + try { + Map dataBaseMap = dataBase.stream().collect(Collectors.toMap(p -> p.getId().toString(), + p2 -> GenerateCollocationDataBaseDTO.builder() + .category(tProductIdToAttributeItemNewMap.get(p2.getId())) + .path(p2.getPictureUrl()).build(), (v1, v2) -> v2)); + //推荐搭配 + List collocationOutResult = pythonService.generateCollocation( + validateList.stream() + .map(product1 -> + GenerateCollocationQueryDTO.builder() + .item_category(tProductIdToAttributeItemNewMap.get(product1.getId())) + .path(product1.getPictureUrl()) + .item_id(product1.getId().toString()).build()) + .collect(Collectors.toList()), dataBaseMap + ); + //保存搭配数据 + tProductAssortmentService.saveBatch( + resolveProductAssortment(collocationOutResult, dataBaseMap, "Asia/Shanghai")); + //更新商品的搭配状态为已搭配 + validateList.stream().forEach(pro -> pro.setCollocationState(1)); + this.updateBatchById(validateList); + } catch (Exception e) { + log.info("定时任务商品搭配异常###{}", ExceptionUtil.stacktraceToString(e)); + } + }); + + } + } + + public Set getCategory(String category) { + List storeVOS = storeService.queryUserStore(null, null); + List productIds = tProductStockService.findByStoreIds(storeVOS.stream().map(StoreVO::getId).collect(Collectors.toList())); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().in(MiTuProduct::getProductId, productIds); + qw.lambda().like(MiTuProduct::getItemGroup, category); + List miTuProductList = miTuProductMapper.selectList(qw); + return miTuProductList.stream().map(MiTuProduct::getItemGroup).collect(Collectors.toSet()); + } +} diff --git a/src/main/java/com/mixi/service/TProductStockService.java b/src/main/java/com/mixi/service/TProductStockService.java new file mode 100644 index 0000000..d01856b --- /dev/null +++ b/src/main/java/com/mixi/service/TProductStockService.java @@ -0,0 +1,55 @@ +package com.mixi.service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mixi.mapper.TProductStockMapper; +import com.mixi.mapper.entity.TProduct; +import com.mixi.mapper.entity.TProductLabel; +import com.mixi.mapper.entity.TProductStock; +import com.mixi.model.dto.StoreDeleteDTO; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + + +/** + *

+ * 商品库存关联表 服务类 + *

+ * + * @author yanglei + * @since 2023-03-15 + */ +@Service +public class TProductStockService extends ServiceImpl { + @Resource + private TProductStockMapper tProductStockMapper; + + @Transactional + public Boolean deleteByProductId(String productId) { + QueryWrapper query = new QueryWrapper<>(); + query.eq("product_id",productId); + tProductStockMapper.delete(query); + return Boolean.TRUE; + } + public List findByStoreIds(List storeIds) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("store_id", storeIds); + List result = tProductStockMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(result)?null : + result.stream().map(TProductStock::getProductId).distinct().collect(Collectors.toList()); + + } + public List findByProductIds(List productIds) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in("product_id", productIds); + List result = tProductStockMapper.selectList(queryWrapper); + return CollectionUtils.isEmpty(result)?null :result; + + } +} diff --git a/src/main/java/com/mixi/service/impl/MiTuExportServiceImpl.java b/src/main/java/com/mixi/service/impl/MiTuExportServiceImpl.java new file mode 100644 index 0000000..603f006 --- /dev/null +++ b/src/main/java/com/mixi/service/impl/MiTuExportServiceImpl.java @@ -0,0 +1,102 @@ +package com.mixi.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.mixi.common.config.exception.BusinessException; +import com.mixi.common.response.PageBaseResponse; +import com.mixi.common.response.Response; +import com.mixi.mapper.MiTuExportMapper; +import com.mixi.mapper.entity.MiTuExport; +import com.mixi.model.dto.QueryMiTuExportPageDTO; +import com.mixi.service.MiTuExportService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.io.InputStreamResource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +//import com.ai.da.common.utils.SendSmsUtil; + +/** + * 服务实现类 + * + * @author easy-generator + * @since 2022-07-06 + */ +@Slf4j +@Service +public class MiTuExportServiceImpl implements MiTuExportService { + + @Resource + private MiTuExportMapper miTuExportMapper; + + @Override + public PageBaseResponse queryMiTuExportPage(QueryMiTuExportPageDTO query) { + // 分页数据 + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(MiTuExport::getStatus, 1); + qw.lambda().like(!StringUtils.isEmpty(query.getFileName()), MiTuExport::getExportName, query.getFileName()); + qw.lambda().eq(!StringUtils.isEmpty(query.getSpan()), MiTuExport::getSpan, query.getSpan()); + // 时间筛选条件 + if (query.getStartTime() != null) { + qw.lambda().ge(MiTuExport::getCreateTime, query.getStartTime()); + } + if (query.getEndTime() != null) { + qw.lambda().le(MiTuExport::getCreateTime, query.getEndTime()); + } + IPage page = miTuExportMapper.selectPage( + new Page<>(query.getPage(), query.getSize()), qw); +// IPage convert = page.convert((Function) +// store -> +// { +// LabelVO result = CopyUtil.copyObject(store, LabelVO.class); +// result.setId(store.getId().toString()); +// result.setCreateUserName(idToNameMap.get(store.getCreateUser())); +// result.setCreateDate(store.getCreateDate().getTime()); +// return result; +// }); + return PageBaseResponse.success(page); +// return miTuExportMapper.selectPage(); + } + + @Override + public void exportMiTuReport(Long id, HttpServletResponse response) throws FileNotFoundException { + MiTuExport miTuExport = miTuExportMapper.selectById(id); + if (ObjectUtils.isEmpty(miTuExport)) { + throw new BusinessException("Report is not exist"); + } + String filePath = miTuExport.getUrl(); // 获取文件路径 + + // 读取文件 + File file = new File(filePath); + InputStream inputStream = new FileInputStream(file); + + // 设置响应头 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename=" + file.getName()); + + // 将文件内容写入响应输出流 + try { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + response.getOutputStream().write(buffer, 0, bytesRead); + } + inputStream.close(); + response.getOutputStream().flush(); + } catch (Exception e) { + throw new RuntimeException("Failed to export report", e); + } + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..638dd7b --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,49 @@ +server.port=5560 + +#datasource +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +spring.datasource.url=jdbc:mysql://18.167.251.121:3306/mixi?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true +spring.datasource.username=root +spring.datasource.password=QWa998345 + +#security +spring.security.jwtSecret=JWTSECRET +spring.security.jwtTokenHeader=Authorization +spring.security.jwtTokenPrefix=Bearer- +## 24��? +spring.security.jwtExpiration=8640000000 +#spring security Full authentication is required to access this resource +spring.security.ignorePaths=/,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs,\ + /api/account/**,/api/label/**,/api/python/**,/api/role/**,/api/product/**,/api/store/**,/api/attribute/**,\ + /api/app/account/**,/api/app/product/**,/api/app/custom/**,/api/miTuExport/** +spring.security.authApi=/auth/login +#请求超级 6000秒 +spring.mvc.async.request-timeout=6000000 +#配置http会话超时 +server.servlet.session.timeout=6000s + + +rsa.private_key=MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== + +#mybatis +mybatis-plus.global-config.banner=false +mybatis-plus.mapper-locations=classpath:mapper/*Mapper.xml +#mybatis-plus.configuration.log-impl= org.apache.ibatis.logging.stdout.StdOutImpl + +spring.mvc.pathmatch.matching-strategy=ant_path_matcher + +file.mac.path=~/file/ +file.linux.path=/workspace/home/mixi/file/ +#linux服务器域名(预览和下载用) +file.linuxDomain=http://18.167.251.121:5568/download/ +file.windows.path=D:\\upload\\mixi\\ +#单个文件最大上传大小 +spring.servlet.multipart.max-file-size = 20MB +#每次请求上传文件最大值 +spring.servlet.multipart.max-request-size= 20MB +#访问python服务的ip(对应环境) +access.python.ip=http://18.167.251.121 + +minio.endpoint=http://18.167.251.121:8000 +minio.accessKey=admin +minio.secretKey=admin123 diff --git a/src/main/resources/mapper/AccountMapper.xml b/src/main/resources/mapper/AccountMapper.xml new file mode 100644 index 0000000..3529c38 --- /dev/null +++ b/src/main/resources/mapper/AccountMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +