Compare commits
32 Commits
3892fffa37
...
master_lz
| Author | SHA1 | Date | |
|---|---|---|---|
| cd1ba55b26 | |||
|
|
687be5840e | ||
|
|
d9f808ecc1 | ||
| c1d84aaf81 | |||
|
|
dec15eb913 | ||
| 18e014d9cb | |||
| 2cb03b146a | |||
|
|
7d48c78c9b | ||
|
|
c80dce6419 | ||
|
|
4802e11f7c | ||
|
|
fde2f18ff5 | ||
|
|
41e0b0b5b4 | ||
|
|
fb05360c5e | ||
| df9479f870 | |||
| e4d6de61ae | |||
| 73c1bc9d01 | |||
|
|
ae9a607da1 | ||
| 32f88b1443 | |||
|
|
c59df81b38 | ||
|
|
66449b0482 | ||
| 5726239eda | |||
| 656267e6b7 | |||
|
|
381c1638e3 | ||
| d95f527938 | |||
| 97df87eb06 | |||
|
|
b98a0f06ba | ||
|
|
15af775af4 | ||
|
|
85e9e5d110 | ||
| b37300ef8c | |||
| b54e1e314a | |||
| 3082c24e13 | |||
|
|
7e7db23d82 |
@@ -119,5 +119,10 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.100.Final</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -155,5 +155,12 @@
|
||||
<artifactId>spring-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.1.100.Final</version> <!-- 使用较新稳定版本 -->
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -21,5 +21,11 @@
|
||||
<groupId>top.wms</groupId>
|
||||
<artifactId>wms-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -18,5 +18,12 @@
|
||||
<groupId>top.wms</groupId>
|
||||
<artifactId>wms-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
<version>1.3.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -13,7 +13,6 @@ import top.wms.admin.common.context.UserContext;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.common.context.UserExtraContext;
|
||||
import top.wms.admin.common.enums.DisEnableStatusEnum;
|
||||
import top.wms.admin.system.model.entity.DeptDO;
|
||||
import top.wms.admin.system.model.entity.UserDO;
|
||||
import top.wms.admin.system.model.resp.ClientResp;
|
||||
import top.wms.admin.system.service.DeptService;
|
||||
@@ -106,7 +105,7 @@ public abstract class AbstractLoginHandler<T extends LoginReq> implements LoginH
|
||||
*/
|
||||
protected void checkUserStatus(UserDO user) {
|
||||
CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, user.getStatus(), "此账号已被禁用,如有疑问,请联系管理员");
|
||||
DeptDO dept = deptService.getById(user.getDeptId());
|
||||
CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, dept.getStatus(), "此账号所属部门已被禁用,如有疑问,请联系管理员");
|
||||
// DeptDO dept = deptService.getById(user.getDeptId());
|
||||
// CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, dept.getStatus(), "此账号所属部门已被禁用,如有疑问,请联系管理员");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,12 @@ public enum AuthTypeEnum implements BaseEnum<String> {
|
||||
/**
|
||||
* 第三方账号
|
||||
*/
|
||||
SOCIAL("SOCIAL", "第三方账号", UiConstants.COLOR_ERROR);
|
||||
SOCIAL("SOCIAL", "第三方账号", UiConstants.COLOR_ERROR),
|
||||
|
||||
/**
|
||||
* 卡号
|
||||
*/
|
||||
CARD("CARD", "卡号", UiConstants.COLOR_PRIMARY);
|
||||
|
||||
private final String value;
|
||||
private final String description;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package top.wms.admin.auth.handler;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.wms.admin.auth.AbstractLoginHandler;
|
||||
import top.wms.admin.auth.enums.AuthTypeEnum;
|
||||
import top.wms.admin.auth.model.req.CardLoginReq;
|
||||
import top.wms.admin.auth.model.resp.LoginResp;
|
||||
import top.wms.admin.system.model.entity.UserDO;
|
||||
import top.wms.admin.system.model.resp.ClientResp;
|
||||
|
||||
@Component
|
||||
public class CardLoginHandler extends AbstractLoginHandler<CardLoginReq> {
|
||||
|
||||
@Override
|
||||
public LoginResp login(CardLoginReq req, ClientResp client, HttpServletRequest request) {
|
||||
// 验证手机号
|
||||
UserDO user = userService.getByCard(req.getCardNumber());
|
||||
ValidationUtils.throwIfNull(user, "此卡号未绑定本系统账号");
|
||||
// 检查用户状态
|
||||
super.checkUserStatus(user);
|
||||
// 执行认证
|
||||
String token = super.authenticate(user, client);
|
||||
return LoginResp.builder().token(token).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preLogin(CardLoginReq req, ClientResp client, HttpServletRequest request) {
|
||||
super.preLogin(req, client, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthTypeEnum getAuthType() {
|
||||
return AuthTypeEnum.CARD;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package top.wms.admin.auth.handler;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
@@ -23,24 +22,18 @@ import top.wms.admin.common.constant.RegexConstants;
|
||||
import top.wms.admin.common.constant.SysConstants;
|
||||
import top.wms.admin.common.enums.DisEnableStatusEnum;
|
||||
import top.wms.admin.common.enums.GenderEnum;
|
||||
import top.wms.admin.system.enums.MessageTemplateEnum;
|
||||
import top.wms.admin.system.enums.MessageTypeEnum;
|
||||
import top.wms.admin.system.model.entity.RoleDO;
|
||||
import top.wms.admin.system.model.entity.UserDO;
|
||||
import top.wms.admin.system.model.entity.UserSocialDO;
|
||||
import top.wms.admin.system.model.req.MessageReq;
|
||||
import top.wms.admin.system.model.resp.ClientResp;
|
||||
import top.wms.admin.system.service.MessageService;
|
||||
import top.wms.admin.system.service.UserRoleService;
|
||||
import top.wms.admin.system.service.UserSocialService;
|
||||
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
|
||||
import top.continew.starter.core.exception.BadRequestException;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.messaging.websocket.util.WebSocketUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 第三方账号登录处理器
|
||||
@@ -56,7 +49,6 @@ public class SocialLoginHandler extends AbstractLoginHandler<SocialLoginReq> {
|
||||
private final AuthRequestFactory authRequestFactory;
|
||||
private final UserSocialService userSocialService;
|
||||
private final UserRoleService userRoleService;
|
||||
private final MessageService messageService;
|
||||
private final ProjectProperties projectProperties;
|
||||
|
||||
@Override
|
||||
@@ -76,21 +68,15 @@ public class SocialLoginHandler extends AbstractLoginHandler<SocialLoginReq> {
|
||||
UserDO user;
|
||||
if (null == userSocial) {
|
||||
String username = authUser.getUsername();
|
||||
String nickname = authUser.getNickname();
|
||||
UserDO existsUser = userService.getByUsername(username);
|
||||
String randomStr = RandomUtil.randomString(RandomUtil.BASE_CHAR, 5);
|
||||
if (null != existsUser || !ReUtil.isMatch(RegexConstants.USERNAME, username)) {
|
||||
username = randomStr + IdUtil.fastSimpleUUID();
|
||||
}
|
||||
if (!ReUtil.isMatch(RegexConstants.GENERAL_NAME, nickname)) {
|
||||
nickname = source.toLowerCase() + randomStr;
|
||||
}
|
||||
user = new UserDO();
|
||||
user.setUsername(username);
|
||||
user.setNickname(nickname);
|
||||
user.setGender(GenderEnum.valueOf(authUser.getGender().name()));
|
||||
user.setAvatar(authUser.getAvatar());
|
||||
user.setDeptId(SysConstants.SUPER_DEPT_ID);
|
||||
user.setStatus(DisEnableStatusEnum.ENABLE);
|
||||
userService.save(user);
|
||||
Long userId = user.getId();
|
||||
@@ -100,7 +86,6 @@ public class SocialLoginHandler extends AbstractLoginHandler<SocialLoginReq> {
|
||||
userSocial.setUserId(userId);
|
||||
userSocial.setSource(source);
|
||||
userSocial.setOpenId(openId);
|
||||
this.sendSecurityMsg(user);
|
||||
} else {
|
||||
user = BeanUtil.copyProperties(userService.getById(userSocial.getUserId()), UserDO.class);
|
||||
}
|
||||
@@ -141,21 +126,4 @@ public class SocialLoginHandler extends AbstractLoginHandler<SocialLoginReq> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送安全消息
|
||||
*
|
||||
* @param user 用户信息
|
||||
*/
|
||||
private void sendSecurityMsg(UserDO user) {
|
||||
MessageReq req = new MessageReq();
|
||||
MessageTemplateEnum socialRegister = MessageTemplateEnum.SOCIAL_REGISTER;
|
||||
req.setTitle(socialRegister.getTitle().formatted(projectProperties.getName()));
|
||||
req.setContent(socialRegister.getContent().formatted(user.getNickname()));
|
||||
req.setType(MessageTypeEnum.SECURITY);
|
||||
messageService.add(req, CollUtil.toList(user.getId()));
|
||||
List<String> tokenList = StpUtil.getTokenValueListByLoginId(user.getId());
|
||||
for (String token : tokenList) {
|
||||
WebSocketUtils.sendMessage(token, "1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package top.wms.admin.auth.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* 卡号登录参数
|
||||
*
|
||||
* @author KAI
|
||||
* @author Charles7c
|
||||
* @since 2024/12/25 15:43
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "卡号登录参数")
|
||||
public class CardLoginReq extends LoginReq {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 卡号
|
||||
*/
|
||||
@Schema(description = "卡号", example = "1234567890")
|
||||
@NotBlank(message = "卡号不能为空")
|
||||
private String cardNumber;
|
||||
|
||||
}
|
||||
@@ -23,7 +23,8 @@ import java.io.Serializable;
|
||||
@JsonSubTypes({@JsonSubTypes.Type(value = AccountLoginReq.class, name = "ACCOUNT"),
|
||||
@JsonSubTypes.Type(value = EmailLoginReq.class, name = "EMAIL"),
|
||||
@JsonSubTypes.Type(value = PhoneLoginReq.class, name = "PHONE"),
|
||||
@JsonSubTypes.Type(value = SocialLoginReq.class, name = "SOCIAL")})
|
||||
@JsonSubTypes.Type(value = SocialLoginReq.class, name = "SOCIAL"),
|
||||
@JsonSubTypes.Type(value = CardLoginReq.class, name = "CARD")})
|
||||
@Schema(description = "基础登录参数")
|
||||
public class LoginReq implements Serializable {
|
||||
|
||||
|
||||
@@ -38,12 +38,6 @@ public class UserInfoResp implements Serializable {
|
||||
@Schema(description = "用户名", example = "zhangsan")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
@Schema(description = "昵称", example = "张三")
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,8 @@ import top.continew.starter.data.mp.base.BaseMapper;
|
||||
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 物料信息 Mapper
|
||||
*
|
||||
@@ -12,5 +14,7 @@ import org.springframework.stereotype.Repository;
|
||||
*/
|
||||
@Repository
|
||||
public interface MaterialInfoMapper extends BaseMapper<MaterialInfoDO> {
|
||||
public int updateByName(List<MaterialInfoDO> list);
|
||||
|
||||
public int updateByCode(List<MaterialInfoDO> list);
|
||||
}
|
||||
|
||||
@@ -37,10 +37,10 @@ public class MaterialInfoDO extends BaseDO {
|
||||
*/
|
||||
private BigDecimal unitWeight;
|
||||
|
||||
/**
|
||||
* 物料单次可称量最大重量(kg)
|
||||
*/
|
||||
private BigDecimal maxWeight;
|
||||
/*
|
||||
物料规格
|
||||
*/
|
||||
private String materialSpec;
|
||||
|
||||
/**
|
||||
* 物料照片地址
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package top.wms.admin.material.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@Schema(description = "物料信息导入行数据")
|
||||
public class MaterialImportRowReq implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 物料名称
|
||||
*/
|
||||
@Schema(description = "物料名称")
|
||||
@NotBlank(message = "物料名称不能为空")
|
||||
@Length(max = 255, message = "物料名称长度不能超过 {max} 个字符")
|
||||
private String materialName;
|
||||
|
||||
/**
|
||||
* 物料编码
|
||||
*/
|
||||
@Schema(description = "物料编码")
|
||||
@NotBlank(message = "物料编码不能为空")
|
||||
@Length(max = 255, message = "物料编码长度不能超过 {max} 个字符")
|
||||
private String encoding;
|
||||
|
||||
/**
|
||||
* 物料单位重量(g)
|
||||
*/
|
||||
@Schema(description = "物料单位重量(g)")
|
||||
private BigDecimal unitWeight;
|
||||
|
||||
/*
|
||||
* 物料规格
|
||||
* */
|
||||
@Schema(description = "物料规格")
|
||||
private String materialSpec;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package top.wms.admin.material.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.common.enums.DisEnableStatusEnum;
|
||||
import top.wms.admin.system.enums.ImportPolicyEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Schema(description = "物料导入参数")
|
||||
public class MaterialInfoImportReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 导入会话KEY
|
||||
*/
|
||||
@Schema(description = "导入会话KEY", example = "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed")
|
||||
@NotBlank(message = "导入已过期,请重新上传")
|
||||
private String importKey;
|
||||
|
||||
/**
|
||||
* 物料名称重复策略
|
||||
*/
|
||||
@Schema(description = "物料名称重复策略", example = "1")
|
||||
@NotNull(message = "物料名称重复策略不能为空")
|
||||
private ImportPolicyEnum duplicateName;
|
||||
|
||||
/**
|
||||
* 重复编码策略
|
||||
*/
|
||||
@Schema(description = "重复编码策略", example = "1")
|
||||
@NotNull(message = "重复编码策略不能为空")
|
||||
private ImportPolicyEnum duplicateCode;
|
||||
|
||||
/**
|
||||
* 默认状态
|
||||
*/
|
||||
@Schema(description = "默认状态", example = "1")
|
||||
private DisEnableStatusEnum defaultStatus;
|
||||
|
||||
}
|
||||
@@ -46,11 +46,11 @@ public class MaterialInfoReq implements Serializable {
|
||||
@Schema(description = "物料单位重量(g)")
|
||||
private Double unitWeight;
|
||||
|
||||
/**
|
||||
* 物料单次可称量最大重量(kg)
|
||||
*/
|
||||
@Schema(description = "物料单次可称量最大重量(kg)")
|
||||
private Double maxWeight;
|
||||
/*
|
||||
* 物料规格
|
||||
* */
|
||||
@Schema(description = "物料规格")
|
||||
private String materialSpec;
|
||||
|
||||
/**
|
||||
* 物料照片地址
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package top.wms.admin.material.model.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 物料导入解析结果
|
||||
*
|
||||
* @author kils
|
||||
* @since 2024/6/18 14:37
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Schema(description = "用户导入解析结果")
|
||||
public class MaterialImportParseResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 导入会话 Key
|
||||
*/
|
||||
@Schema(description = "导入会话Key", example = "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed")
|
||||
private String importKey;
|
||||
|
||||
/**
|
||||
* 总计行数
|
||||
*/
|
||||
@Schema(description = "总计行数", example = "100")
|
||||
private Integer totalRows;
|
||||
|
||||
/**
|
||||
* 有效行数
|
||||
*/
|
||||
@Schema(description = "有效行数", example = "100")
|
||||
private Integer validRows;
|
||||
|
||||
/**
|
||||
* 重复物料名行数
|
||||
*/
|
||||
@Schema(description = "重复物料名行数", example = "100")
|
||||
private Integer duplicateNameRows;
|
||||
|
||||
/**
|
||||
* 重复物料编码行数
|
||||
*/
|
||||
@Schema(description = "重复物料编码行数", example = "100")
|
||||
private Integer duplicateCodeRows;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package top.wms.admin.material.model.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@Schema(description = "物料信息导入结果")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MaterialInfoImportResp implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 总计行数
|
||||
*/
|
||||
@Schema(description = "总计行数", example = "100")
|
||||
private Integer totalRows;
|
||||
|
||||
/**
|
||||
* 新增行数
|
||||
*/
|
||||
@Schema(description = "新增行数", example = "100")
|
||||
private Integer insertRows;
|
||||
|
||||
/**
|
||||
* 修改行数
|
||||
*/
|
||||
@Schema(description = "修改行数", example = "100")
|
||||
private Integer updateRows;
|
||||
}
|
||||
@@ -45,11 +45,11 @@ public class MaterialInfoResp extends BaseDetailResp {
|
||||
private Double unitWeight;
|
||||
|
||||
/**
|
||||
* 物料单次可称量最大重量(kg)
|
||||
* 物料规格
|
||||
*/
|
||||
@Schema(description = "物料单次可称量最大重量(kg)")
|
||||
@ExcelProperty(value = "物料单次可称量最大重量(kg)")
|
||||
private Double maxWeight;
|
||||
@Schema(description = "物料规格")
|
||||
@ExcelProperty(value = "物料规格")
|
||||
private String materialSpec;
|
||||
|
||||
/**
|
||||
* 物料照片地址
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package top.wms.admin.material.service;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.starter.extension.crud.service.BaseService;
|
||||
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
||||
import top.wms.admin.material.model.query.MaterialInfoQuery;
|
||||
import top.wms.admin.material.model.req.MaterialInfoImportReq;
|
||||
import top.wms.admin.material.model.req.MaterialInfoReq;
|
||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 物料信息业务接口
|
||||
*
|
||||
@@ -13,4 +21,43 @@ import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||
*/
|
||||
public interface MaterialInfoService extends BaseService<MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> {
|
||||
|
||||
/*
|
||||
*
|
||||
* 根据编码查询物料信息
|
||||
* */
|
||||
public MaterialInfoDO getMaterialInfoByCode(String code);
|
||||
|
||||
/**
|
||||
* 下载导入模板
|
||||
*
|
||||
* @param response 响应对象
|
||||
* @throws IOException /
|
||||
*/
|
||||
void downloadImportTemplate(HttpServletResponse response) throws IOException;
|
||||
|
||||
/**
|
||||
* 解析导入数据
|
||||
*
|
||||
* @param file 导入文件
|
||||
* @return 解析结果
|
||||
*/
|
||||
MaterialImportParseResp parseImport(MultipartFile file);
|
||||
|
||||
/**
|
||||
* 导入数据
|
||||
*
|
||||
* @param req 导入信息
|
||||
* @return 导入结果
|
||||
*/
|
||||
MaterialInfoImportResp importMaterial(MaterialInfoImportReq req);
|
||||
|
||||
/*
|
||||
* 照片批量上传处理
|
||||
* */
|
||||
void uploadMaterialPhotos(MultipartFile file);
|
||||
|
||||
/*
|
||||
* 称重时照片抓取
|
||||
* */
|
||||
String catchPhoto(MultipartFile file);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,63 @@
|
||||
package top.wms.admin.material.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.extra.validation.ValidationUtil;
|
||||
import cn.hutool.http.ContentType;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.dreamlu.mica.core.result.R;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.starter.cache.redisson.util.RedisUtils;
|
||||
import top.continew.starter.core.exception.BusinessException;
|
||||
import top.continew.starter.core.validation.CheckUtils;
|
||||
import top.continew.starter.extension.crud.service.BaseServiceImpl;
|
||||
import top.continew.starter.web.util.FileUploadUtils;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.common.util.SecureUtils;
|
||||
import top.wms.admin.material.mapper.MaterialInfoMapper;
|
||||
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
||||
import top.wms.admin.material.model.query.MaterialInfoQuery;
|
||||
import top.wms.admin.material.model.req.MaterialImportRowReq;
|
||||
import top.wms.admin.material.model.req.MaterialInfoImportReq;
|
||||
import top.wms.admin.material.model.req.MaterialInfoReq;
|
||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||
import top.wms.admin.material.service.MaterialInfoService;
|
||||
import top.wms.admin.system.service.FileService;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static top.wms.admin.system.enums.ImportPolicyEnum.*;
|
||||
import static top.wms.admin.system.enums.ImportPolicyEnum.SKIP;
|
||||
|
||||
/**
|
||||
* 物料信息业务实现
|
||||
@@ -20,6 +67,358 @@ import top.wms.admin.material.service.MaterialInfoService;
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MaterialInfoServiceImpl extends BaseServiceImpl<MaterialInfoMapper, MaterialInfoDO, MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> implements MaterialInfoService {
|
||||
|
||||
private static final Set<String> IMAGE_EXTENSIONS = Set.of("jpg", "jpeg", "png", "gif", "bmp");
|
||||
|
||||
private final FileService fileService;
|
||||
|
||||
@Override
|
||||
public MaterialInfoDO getMaterialInfoByCode(String code) {
|
||||
if (StrUtil.isNotBlank(code)) {
|
||||
return baseMapper.lambdaQuery().eq(MaterialInfoDO::getEncoding, code).one();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
|
||||
try {
|
||||
FileUploadUtils.download(response, ResourceUtil
|
||||
.getStream("templates/import/materialInfo.xlsx"), "物料信息导入模板.xlsx");
|
||||
} catch (Exception e) {
|
||||
log.error("下载用户导入模板失败:{}", e);
|
||||
response.setCharacterEncoding(CharsetUtil.UTF_8);
|
||||
response.setContentType(ContentType.JSON.toString());
|
||||
response.getWriter().write(JSONUtil.toJsonStr(R.fail("下载用户导入模板失败")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialImportParseResp parseImport(MultipartFile file) {
|
||||
MaterialImportParseResp materialImportResp = new MaterialImportParseResp();
|
||||
List<MaterialImportRowReq> importRowList;
|
||||
// 读取表格数据
|
||||
try {
|
||||
importRowList = EasyExcel.read(file.getInputStream())
|
||||
.head(MaterialImportRowReq.class)
|
||||
.sheet()
|
||||
.headRowNumber(1)
|
||||
.doReadSync();
|
||||
} catch (Exception e) {
|
||||
log.error("物料信息导入数据文件解析异常:{}", e);
|
||||
throw new BusinessException("数据文件解析异常");
|
||||
}
|
||||
// 总计行数
|
||||
materialImportResp.setTotalRows(importRowList.size());
|
||||
CheckUtils.throwIfEmpty(importRowList, "数据文件格式错误");
|
||||
// 有效行数:过滤无效(同名物料)数据
|
||||
List<MaterialImportRowReq> validRowList = this.filterImportData(importRowList);
|
||||
materialImportResp.setValidRows(validRowList.size());
|
||||
CheckUtils.throwIfEmpty(validRowList, "数据文件格式错误");
|
||||
|
||||
// 检测表格内数据是否合法
|
||||
Set<String> seenCode = new HashSet<>();
|
||||
boolean hasDuplicateEncoding = validRowList.stream()
|
||||
.map(MaterialImportRowReq::getEncoding)
|
||||
.anyMatch(encoding -> encoding != null && !seenCode.add(encoding));
|
||||
CheckUtils.throwIf(hasDuplicateEncoding, "存在重复物料编码,请检测数据");
|
||||
|
||||
// 查询重复用户
|
||||
materialImportResp
|
||||
.setDuplicateNameRows(countExistByField(validRowList, MaterialImportRowReq::getMaterialName, MaterialInfoDO::getMaterialName, false));
|
||||
// 查询重复邮箱
|
||||
materialImportResp
|
||||
.setDuplicateCodeRows(countExistByField(validRowList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding, false));
|
||||
// 设置导入会话并缓存数据,有效期10分钟
|
||||
String importKey = UUID.fastUUID().toString(true);
|
||||
RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(validRowList), Duration
|
||||
.ofMinutes(10));
|
||||
materialImportResp.setImportKey(importKey);
|
||||
return materialImportResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public MaterialInfoImportResp importMaterial(MaterialInfoImportReq req) {
|
||||
// 校验导入会话是否过期
|
||||
List<MaterialImportRowReq> importMaterialList;
|
||||
try {
|
||||
String data = RedisUtils.get(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
|
||||
importMaterialList = JSONUtil.toList(data, MaterialImportRowReq.class);
|
||||
CheckUtils.throwIf(CollUtil.isEmpty(importMaterialList), "导入已过期,请重新上传");
|
||||
} catch (Exception e) {
|
||||
log.error("导入异常:", e);
|
||||
throw new BusinessException("导入已过期,请重新上传");
|
||||
}
|
||||
// 已存在数据查询
|
||||
List<String> existName = listExistByField(importMaterialList, MaterialImportRowReq::getMaterialName, MaterialInfoDO::getMaterialName);
|
||||
List<String> existCode = listExistByField(importMaterialList, MaterialImportRowReq::getEncoding, MaterialInfoDO::getEncoding);
|
||||
CheckUtils.throwIf(isExitImportMaterial(req, importMaterialList, existName, existCode), "数据不符合导入策略,已退出导入");
|
||||
// 批量操作数据库集合
|
||||
List<MaterialInfoDO> insertList = new ArrayList<>();
|
||||
List<MaterialInfoDO> updateByNameList = new ArrayList<>();
|
||||
List<MaterialInfoDO> updateByCodeList = new ArrayList<>();
|
||||
// ID生成器
|
||||
// IdGenerator idGenerator = DefaultIdGeneratorProvider.INSTANCE.getShare();
|
||||
for (MaterialImportRowReq row : importMaterialList) {
|
||||
if (isSkipMaterialImport(req, row, existName, existCode)) {
|
||||
// 按规则跳过该行
|
||||
continue;
|
||||
}
|
||||
MaterialInfoDO materialDO = BeanUtil.toBeanIgnoreError(row, MaterialInfoDO.class);
|
||||
materialDO.setUnitWeight(NumberUtil.isValidNumber(row.getUnitWeight()) ? row.getUnitWeight() : null);
|
||||
materialDO.setMaterialSpec(StrUtil.isNotBlank(row.getMaterialSpec()) ? row.getMaterialSpec() : null);
|
||||
// 修改 or 新增
|
||||
if (UPDATE.validate(req.getDuplicateName(), row.getMaterialName(), existName)) {
|
||||
materialDO.setMaterialName(row.getMaterialName());
|
||||
materialDO.setUpdateTime(LocalDateTime.now());
|
||||
materialDO.setUpdateUser(UserContextHolder.getUserId());
|
||||
updateByNameList.add(materialDO);
|
||||
} else if (UPDATE.validate(req.getDuplicateCode(), row.getEncoding(), existCode)) {
|
||||
materialDO.setEncoding(row.getEncoding());
|
||||
materialDO.setUpdateTime(LocalDateTime.now());
|
||||
materialDO.setUpdateUser(UserContextHolder.getUserId());
|
||||
updateByCodeList.add(materialDO);
|
||||
} else {
|
||||
// materialDO.setId(idGenerator.generate());
|
||||
insertList.add(materialDO);
|
||||
}
|
||||
}
|
||||
doImportMaterial(insertList, updateByNameList, updateByCodeList);
|
||||
RedisUtils.delete(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
|
||||
int insertCount = insertList.size();
|
||||
int updateByNameCount = updateByNameList.size();
|
||||
int updateByCodeCount = updateByCodeList.size();
|
||||
int totalUpdateCount = updateByNameCount + updateByCodeCount;
|
||||
int totalHandleCount = insertCount + totalUpdateCount;
|
||||
return new MaterialInfoImportResp(totalHandleCount, // 总处理数
|
||||
insertCount, // 新增数
|
||||
totalUpdateCount // 更新总数
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按指定数据集获取数据库已存在的数量
|
||||
*
|
||||
* @param materialRowList 导入的数据源
|
||||
* @param rowField 导入数据的字段
|
||||
* @param dbField 对比数据库的字段
|
||||
* @return 存在的数量
|
||||
*/
|
||||
private int countExistByField(List<MaterialImportRowReq> materialRowList,
|
||||
Function<MaterialImportRowReq, String> rowField,
|
||||
SFunction<MaterialInfoDO, ?> dbField,
|
||||
boolean fieldEncrypt) {
|
||||
List<String> fieldValues = materialRowList.stream().map(rowField).filter(Objects::nonNull).toList();
|
||||
if (fieldValues.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return (int)this.count(Wrappers.<MaterialInfoDO>lambdaQuery()
|
||||
.in(dbField, fieldEncrypt ? SecureUtils.encryptFieldByAes(fieldValues) : fieldValues));
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤无效的导入用户数据(批量导入不严格校验数据)
|
||||
*
|
||||
* @param importRowList 导入数据
|
||||
*/
|
||||
private List<MaterialImportRowReq> filterImportData(List<MaterialImportRowReq> importRowList) {
|
||||
// 校验过滤
|
||||
List<MaterialImportRowReq> list = importRowList.stream()
|
||||
.filter(row -> ValidationUtil.validate(row).isEmpty())
|
||||
.toList();
|
||||
// 物料名去重
|
||||
return list.stream()
|
||||
.collect(Collectors.toMap(MaterialImportRowReq::getMaterialName, row -> row, (existing,
|
||||
replacement) -> existing))
|
||||
.values()
|
||||
.stream()
|
||||
.toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按指定数据集获取数据库已存在内容
|
||||
*
|
||||
* @param materialRowList 导入的数据源
|
||||
* @param rowField 导入数据的字段
|
||||
* @param dbField 对比数据库的字段
|
||||
* @return 存在的内容
|
||||
*/
|
||||
private List<String> listExistByField(List<MaterialImportRowReq> materialRowList,
|
||||
Function<MaterialImportRowReq, String> rowField,
|
||||
SFunction<MaterialInfoDO, String> dbField) {
|
||||
List<String> fieldValues = materialRowList.stream().map(rowField).filter(Objects::nonNull).toList();
|
||||
if (fieldValues.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<MaterialInfoDO> materialDOList = baseMapper.selectList(Wrappers.<MaterialInfoDO>lambdaQuery()
|
||||
.in(dbField, fieldValues)
|
||||
.select(dbField));
|
||||
return materialDOList.stream().map(dbField).filter(Objects::nonNull).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否退出导入
|
||||
*
|
||||
* @param req 导入参数
|
||||
* @param list 导入数据
|
||||
* @param existName 导入数据中已存在的物料名
|
||||
* @param existCode 导入数据中已存在的物料编号
|
||||
* @return 是否退出
|
||||
*/
|
||||
private boolean isExitImportMaterial(MaterialInfoImportReq req,
|
||||
List<MaterialImportRowReq> list,
|
||||
List<String> existName,
|
||||
List<String> existCode) {
|
||||
return list.stream()
|
||||
.anyMatch(row -> EXIT.validate(req.getDuplicateName(), row.getMaterialName(), existName) || EXIT
|
||||
.validate(req.getDuplicateCode(), row.getEncoding(), existCode));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否跳过导入
|
||||
*
|
||||
* @param req 导入参数
|
||||
* @param row 导入数据
|
||||
* @param existName 导入数据中已存在的物料名称
|
||||
* @param existCode 导入数据中已存在的物料编号
|
||||
* @return 是否跳过
|
||||
*/
|
||||
private boolean isSkipMaterialImport(MaterialInfoImportReq req,
|
||||
MaterialImportRowReq row,
|
||||
List<String> existName,
|
||||
List<String> existCode) {
|
||||
return SKIP.validate(req.getDuplicateName(), row.getMaterialName(), existName) || SKIP.validate(req
|
||||
.getDuplicateCode(), row.getEncoding(), existCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入用户
|
||||
*
|
||||
* @param insertList 新增用户
|
||||
* @param updateByNameList 修改用户
|
||||
* @param updateByCodeList 用户角色关联
|
||||
*/
|
||||
private void doImportMaterial(List<MaterialInfoDO> insertList,
|
||||
List<MaterialInfoDO> updateByNameList,
|
||||
List<MaterialInfoDO> updateByCodeList) {
|
||||
if (CollUtil.isNotEmpty(insertList)) {
|
||||
baseMapper.insertBatch(insertList);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(updateByNameList)) {
|
||||
baseMapper.updateByName(updateByNameList);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(updateByCodeList)) {
|
||||
baseMapper.updateByCode(updateByCodeList);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uploadMaterialPhotos(MultipartFile zipFile) {
|
||||
// 1. 初始化物料编码-照片地址Map
|
||||
Map<String, String> codeUrlMap = new HashMap<>();
|
||||
// 物料照片存储路径(自定义,比如按日期分目录)
|
||||
String photoStoragePath = "/" + DateUtil.today() + "/";
|
||||
|
||||
try (ZipInputStream zipInputStream = new ZipInputStream(zipFile.getInputStream())) {
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
||||
// 跳过目录、非图片文件
|
||||
if (zipEntry.isDirectory() || !isImageFile(zipEntry.getName())) {
|
||||
zipInputStream.closeEntry();
|
||||
continue;
|
||||
}
|
||||
// 2. 提取物料编码(照片名 = 物料编码,去掉后缀)
|
||||
String fileName = zipEntry.getName();
|
||||
log.info("正在处理的照片:" + fileName);
|
||||
//去除windows或linux环境下 可能存在的多层级目录
|
||||
if (fileName.contains("/")) {
|
||||
fileName = fileName.substring(fileName.lastIndexOf("/") + 1);
|
||||
}
|
||||
if (fileName.contains("\\")) {
|
||||
fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
|
||||
}
|
||||
String materialCode = fileName.substring(0, fileName.lastIndexOf("."));
|
||||
// 3. 读取ZIP中的图片为BufferedImage
|
||||
BufferedImage image = ImageIO.read(zipInputStream);
|
||||
if (ObjectUtil.isEmpty(image)) {
|
||||
log.warn("无法读取图片: {}", fileName);
|
||||
zipInputStream.closeEntry();
|
||||
continue;
|
||||
}
|
||||
// 4. 将BufferedImage转为字节流
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
String imageExt = getImageExtension(fileName);
|
||||
ImageIO.write(image, imageExt, baos);
|
||||
byte[] imageBytes = baos.toByteArray();
|
||||
|
||||
// 5. 转换为MultipartFile(使用MockMultipartFile)
|
||||
MultipartFile singleImageFile = new MockMultipartFile("file", fileName, "image/" + (imageExt
|
||||
.equals("jpg") ? "jpeg" : imageExt), imageBytes);
|
||||
|
||||
// 6. 调用upload方法上传图片
|
||||
FileInfo fileInfo = fileService.upload(singleImageFile, photoStoragePath, null, true, true);
|
||||
|
||||
// 7. 将物料编码和图片URL存入Map
|
||||
codeUrlMap.put(materialCode, fileInfo.getUrl());
|
||||
|
||||
zipInputStream.closeEntry();
|
||||
}
|
||||
setPhotosByCode(codeUrlMap);
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException("照片批量导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isImageFile(String fileName) {
|
||||
if (fileName == null || !fileName.contains("."))
|
||||
return false;
|
||||
String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
||||
return IMAGE_EXTENSIONS.contains(ext);
|
||||
}
|
||||
|
||||
private String getImageExtension(String fileName) {
|
||||
String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
|
||||
return "jpeg".equals(ext) ? "jpg" : ext;
|
||||
}
|
||||
|
||||
private void setPhotosByCode(Map<String, String> codeUrlMap) {
|
||||
CheckUtils.throwIfEmpty(codeUrlMap, "照片为空,请重新上传");
|
||||
List<MaterialInfoDO> existList = baseMapper.selectList(Wrappers.<MaterialInfoDO>lambdaQuery()
|
||||
.in(MaterialInfoDO::getEncoding, codeUrlMap.keySet()));
|
||||
if (existList.isEmpty()) {
|
||||
log.warn("未找到任何匹配的物料编码");
|
||||
return;
|
||||
}
|
||||
List<MaterialInfoDO> updateList = existList.stream().map(exist -> {
|
||||
MaterialInfoDO updateDO = new MaterialInfoDO();
|
||||
updateDO.setId(exist.getId());
|
||||
updateDO.setPhotoUrl(codeUrlMap.get(exist.getEncoding()));
|
||||
return updateDO;
|
||||
}).collect(Collectors.toList());
|
||||
if (!updateList.isEmpty()) {
|
||||
baseMapper.updateBatchById(updateList);
|
||||
log.info("成功更新 {} 个物料的照片", updateList.size());
|
||||
}
|
||||
|
||||
//记录未找到的物料编码(可选,方便排查问题)
|
||||
Set<String> existCodes = existList.stream().map(MaterialInfoDO::getEncoding).collect(Collectors.toSet());
|
||||
|
||||
codeUrlMap.keySet()
|
||||
.stream()
|
||||
.filter(code -> !existCodes.contains(code))
|
||||
.forEach(code -> log.warn("物料编码 [{}] 不存在,照片更新失败", code));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String catchPhoto(MultipartFile file) {
|
||||
String photoStoragePath = "catch" + DateUtil.today() + "/";
|
||||
FileInfo fileInfo = fileService.upload(file, photoStoragePath, null, true, true);
|
||||
CheckUtils.throwIfNull(fileInfo, "照片上传失败");
|
||||
return fileInfo.getUrl();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
package top.wms.admin.system.mapper;
|
||||
|
||||
import com.alicp.jetcache.anno.Cached;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.system.model.entity.LogDO;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardAccessTrendResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardOverviewCommonResp;
|
||||
import top.wms.admin.system.model.resp.log.LogResp;
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -51,83 +45,4 @@ public interface LogMapper extends BaseMapper<LogDO> {
|
||||
@Select("SELECT COUNT(*) FROM sys_log")
|
||||
Long selectTotalCount();
|
||||
|
||||
/**
|
||||
* 查询仪表盘 PV 总览
|
||||
*
|
||||
* @return 仪表盘 PV 总览
|
||||
*/
|
||||
DashboardOverviewCommonResp selectDashboardOverviewPv();
|
||||
|
||||
/**
|
||||
* 查询仪表盘 IP 总览
|
||||
*
|
||||
* @return 仪表盘 IP 总览
|
||||
*/
|
||||
DashboardOverviewCommonResp selectDashboardOverviewIp();
|
||||
|
||||
/**
|
||||
* 查询仪表盘 PV 近 N 月各月份信息
|
||||
*
|
||||
* @param months 近 N 月月份列表
|
||||
* @return 仪表盘 PV 近 N 月各月份信息
|
||||
*/
|
||||
@Cached(key = "#months[0]", name = CacheConstants.DASHBOARD_KEY_PREFIX + "PV:")
|
||||
List<DashboardChartCommonResp> selectListDashboardAnalysisPv(@Param("months") List<String> months);
|
||||
|
||||
/**
|
||||
* 查询仪表盘 IP 近 N 月各月份信息
|
||||
*
|
||||
* @param months 近 N 月月份列表
|
||||
* @return 仪表盘 IP 近 N 月各月份信息
|
||||
*/
|
||||
@Cached(key = "#months[0]", name = CacheConstants.DASHBOARD_KEY_PREFIX + "IP:")
|
||||
List<DashboardChartCommonResp> selectListDashboardAnalysisIp(@Param("months") List<String> months);
|
||||
|
||||
/**
|
||||
* 查询仪表盘地域分析信息
|
||||
*
|
||||
* @return 仪表盘地域分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> selectListDashboardAnalysisGeo();
|
||||
|
||||
/**
|
||||
* 查询仪表盘访问趋势信息
|
||||
*
|
||||
* @param startTime 开始时间
|
||||
* @param endTime 结束时间
|
||||
* @return 仪表盘访问趋势信息
|
||||
*/
|
||||
List<DashboardAccessTrendResp> selectListDashboardAccessTrend(@Param("startTime") Date startTime,
|
||||
@Param("endTime") Date endTime);
|
||||
|
||||
/**
|
||||
* 查询仪表盘访问时段分析信息
|
||||
*
|
||||
* @return 仪表盘访问时段分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> selectListDashboardAnalysisTimeslot();
|
||||
|
||||
/**
|
||||
* 查询仪表盘模块分析信息
|
||||
*
|
||||
* @param top 显示数量
|
||||
* @return 仪表盘模块分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> selectListDashboardAnalysisModule(@Param("top") Integer top);
|
||||
|
||||
/**
|
||||
* 查询仪表盘终端分析信息
|
||||
*
|
||||
* @param top 显示数量
|
||||
* @return 仪表盘终端分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> selectListDashboardAnalysisOs(@Param("top") Integer top);
|
||||
|
||||
/**
|
||||
* 查询仪表盘浏览器分析信息
|
||||
*
|
||||
* @param top 显示数量
|
||||
* @return 仪表盘浏览器分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> selectListDashboardAnalysisBrowser(@Param("top") Integer top);
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package top.wms.admin.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import top.wms.admin.system.model.entity.MessageDO;
|
||||
import top.wms.admin.system.model.resp.message.MessageResp;
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
|
||||
/**
|
||||
* 消息 Mapper
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
public interface MessageMapper extends BaseMapper<MessageDO> {
|
||||
|
||||
/**
|
||||
* 分页查询列表
|
||||
*
|
||||
* @param page 分页查询条件
|
||||
* @param queryWrapper 查询条件
|
||||
* @return 分页信息
|
||||
*/
|
||||
IPage<MessageResp> selectPageByUserId(@Param("page") IPage<Object> page,
|
||||
@Param(Constants.WRAPPER) QueryWrapper<MessageDO> queryWrapper);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package top.wms.admin.system.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import top.wms.admin.system.model.entity.MessageUserDO;
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
|
||||
/**
|
||||
* 消息和用户 Mapper
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 20:25
|
||||
*/
|
||||
public interface MessageUserMapper extends BaseMapper<MessageUserDO> {
|
||||
|
||||
/**
|
||||
* 根据用户 ID 和消息类型查询未读消息数量
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @param type 消息类型
|
||||
* @return 未读消息信息
|
||||
*/
|
||||
Long selectUnreadCountByUserIdAndType(@Param("userId") Long userId, @Param("type") Integer type);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package top.wms.admin.system.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import top.wms.admin.system.model.entity.NoticeDO;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardNoticeResp;
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公告 Mapper
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
public interface NoticeMapper extends BaseMapper<NoticeDO> {
|
||||
|
||||
/**
|
||||
* 查询仪表盘公告列表
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @return 仪表盘公告列表
|
||||
*/
|
||||
List<DashboardNoticeResp> selectDashboardList(@Param("userId") Long userId);
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package top.wms.admin.system.mapper;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
import top.wms.admin.system.model.entity.RuleRelationDO;
|
||||
|
||||
/**
|
||||
* 通行规则-设备关联 Mapper
|
||||
*
|
||||
* @author zc
|
||||
* @since 2025/12/22 17:16
|
||||
*/
|
||||
@Repository
|
||||
public interface RuleRelationMapper extends BaseMapper<RuleRelationDO> {
|
||||
|
||||
int deleteByRuleId(RuleRelationDO ruleRelation);
|
||||
|
||||
}
|
||||
@@ -94,4 +94,13 @@ public interface UserMapper extends DataPermissionMapper<UserDO> {
|
||||
* @return 用户数量
|
||||
*/
|
||||
Long selectCountByPhone(@FieldEncrypt @Param("phone") String phone, @Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 根据卡片号查询
|
||||
*
|
||||
* @param card 卡片号
|
||||
* @return 用户信息
|
||||
*/
|
||||
@Select("SELECT * FROM sys_user WHERE card_no = #{card}")
|
||||
UserDO selectByCard(@Param("card") String card);
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
package top.wms.admin.system.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.system.enums.MessageTypeEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 消息实体
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_message")
|
||||
public class MessageDO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 类型(1:系统消息)
|
||||
*/
|
||||
private MessageTypeEnum type;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Long createUser;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package top.wms.admin.system.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 消息和用户关联实体
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 20:25
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_message_user")
|
||||
public class MessageUserDO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 消息 ID
|
||||
*/
|
||||
private Long messageId;
|
||||
|
||||
/**
|
||||
* 用户 ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 是否已读
|
||||
*/
|
||||
private Boolean isRead;
|
||||
|
||||
/**
|
||||
* 读取时间
|
||||
*/
|
||||
private LocalDateTime readTime;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
package top.wms.admin.system.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.common.model.entity.BaseDO;
|
||||
import top.wms.admin.system.enums.NoticeScopeEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公告实体
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Data
|
||||
@TableName(value = "sys_notice", autoResultMap = true)
|
||||
public class NoticeDO extends BaseDO {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 生效时间
|
||||
*/
|
||||
private LocalDateTime effectiveTime;
|
||||
|
||||
/**
|
||||
* 终止时间
|
||||
*/
|
||||
private LocalDateTime terminateTime;
|
||||
|
||||
/**
|
||||
* 通知范围
|
||||
*/
|
||||
private NoticeScopeEnum noticeScope;
|
||||
|
||||
/**
|
||||
* 通知用户
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> noticeUsers;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package top.wms.admin.system.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 通行规则-设备关联实体
|
||||
*
|
||||
* @author zc
|
||||
* @since 2025/12/22 17:16
|
||||
*/
|
||||
@Data
|
||||
@TableName("equipment_rule_relation")
|
||||
public class RuleRelationDO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 平台侧规则ID(关联规则表主键)
|
||||
*/
|
||||
private Long ruleId;
|
||||
|
||||
/**
|
||||
* 设备ID(关联设备表主键)
|
||||
*/
|
||||
private Long equipmentId;
|
||||
|
||||
/**
|
||||
* 设备侧的规则ID(设备本地存储的规则标识)
|
||||
*/
|
||||
private String equipmentRuleId;
|
||||
|
||||
}
|
||||
@@ -38,7 +38,6 @@ public class UserDO extends BaseDO {
|
||||
// @FieldEncrypt(encryptor = BCryptEncryptor.class)
|
||||
private String password;
|
||||
|
||||
|
||||
/*
|
||||
* 卡号
|
||||
* */
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
package top.wms.admin.system.model.query;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.system.enums.MessageTypeEnum;
|
||||
import top.continew.starter.data.core.annotation.Query;
|
||||
import top.continew.starter.data.core.annotation.QueryIgnore;
|
||||
import top.continew.starter.data.core.enums.QueryType;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 消息查询条件
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "消息查询条件")
|
||||
public class MessageQuery implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@Schema(description = "ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题", example = "欢迎注册 xxx")
|
||||
@Query(type = QueryType.LIKE)
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
@Schema(description = "类型", example = "1")
|
||||
private MessageTypeEnum type;
|
||||
|
||||
/**
|
||||
* 是否已读
|
||||
*/
|
||||
@Schema(description = "是否已读", example = "true")
|
||||
@QueryIgnore
|
||||
private Boolean isRead;
|
||||
|
||||
/**
|
||||
* 用户 ID
|
||||
*/
|
||||
@Schema(hidden = true)
|
||||
@QueryIgnore
|
||||
private Long userId;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package top.wms.admin.system.model.query;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import top.continew.starter.data.core.annotation.Query;
|
||||
import top.continew.starter.data.core.enums.QueryType;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 公告查询条件
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "公告查询条件")
|
||||
public class NoticeQuery implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题", example = "这是公告标题")
|
||||
@Query(type = QueryType.LIKE)
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
@Schema(description = "类型", example = "1")
|
||||
private String type;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package top.wms.admin.system.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
import top.wms.admin.system.enums.MessageTypeEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 创建消息参数
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "创建消息参数")
|
||||
public class MessageReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题", example = "欢迎注册 xxx")
|
||||
@NotBlank(message = "标题不能为空")
|
||||
@Length(max = 50, message = "标题长度不能超过 {max} 个字符")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
@Schema(description = "内容", example = "尊敬的 xx,欢迎注册使用,请及时配置您的密码。")
|
||||
@NotBlank(message = "内容不能为空")
|
||||
@Length(max = 255, message = "内容长度不能超过 {max} 个字符")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
@Schema(description = "类型(1:系统消息)", example = "1")
|
||||
@NotNull(message = "类型非法")
|
||||
private MessageTypeEnum type;
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package top.wms.admin.system.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.Future;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
import top.wms.admin.system.enums.NoticeScopeEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 创建或修改公告参数
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "创建或修改公告参数")
|
||||
public class NoticeReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题", example = "这是公告标题")
|
||||
@NotBlank(message = "标题不能为空")
|
||||
@Length(max = 150, message = "标题长度不能超过 {max} 个字符")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
@Schema(description = "内容", example = "这是公告内容")
|
||||
@NotBlank(message = "内容不能为空")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 类型(取值于字典 notice_type)
|
||||
*/
|
||||
@Schema(description = "类型(取值于字典 notice_type)", example = "1")
|
||||
@NotBlank(message = "类型不能为空")
|
||||
@Length(max = 30, message = "类型长度不能超过 {max} 个字符")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 生效时间
|
||||
*/
|
||||
@Schema(description = "生效时间", example = "2023-08-08 00:00:00", type = "string")
|
||||
private LocalDateTime effectiveTime;
|
||||
|
||||
/**
|
||||
* 终止时间
|
||||
*/
|
||||
@Schema(description = "终止时间", example = "2023-08-08 23:59:59", type = "string")
|
||||
@Future(message = "终止时间必须是未来时间")
|
||||
private LocalDateTime terminateTime;
|
||||
|
||||
/**
|
||||
* 通知范围
|
||||
*/
|
||||
@Schema(description = "通知范围", example = "2")
|
||||
@NotNull(message = "通知范围不能为空")
|
||||
private NoticeScopeEnum noticeScope;
|
||||
|
||||
/**
|
||||
* 指定用户
|
||||
*/
|
||||
@Schema(description = "指定用户", example = "[1,2,3]")
|
||||
private List<String> noticeUsers;
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
package top.wms.admin.system.model.req;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 创建或修改通行规则-设备关联参数
|
||||
*
|
||||
* @author zc
|
||||
* @since 2025/12/22 17:16
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "创建或修改通行规则-设备关联参数")
|
||||
public class RuleRelationReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 平台侧规则ID(关联规则表主键)
|
||||
*/
|
||||
@Schema(description = "平台侧规则ID(关联规则表主键)")
|
||||
@NotNull(message = "平台侧规则ID(关联规则表主键)不能为空")
|
||||
private Long ruleId;
|
||||
|
||||
/**
|
||||
* 设备ID(关联设备表主键)
|
||||
*/
|
||||
@Schema(description = "设备ID(关联设备表主键)")
|
||||
@NotNull(message = "设备ID(关联设备表主键)不能为空")
|
||||
private Long equipmentId;
|
||||
|
||||
/**
|
||||
* 设备侧的规则ID(设备本地存储的规则标识)
|
||||
*/
|
||||
@Schema(description = "设备侧的规则ID(设备本地存储的规则标识)")
|
||||
@NotBlank(message = "设备侧的规则ID(设备本地存储的规则标识)不能为空")
|
||||
@Length(max = 64, message = "设备侧的规则ID(设备本地存储的规则标识)长度不能超过 {max} 个字符")
|
||||
private String equipmentRuleId;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -25,12 +25,12 @@ public class UserBasicInfoUpdateReq implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
* 用户名
|
||||
*/
|
||||
@Schema(description = "昵称", example = "张三")
|
||||
@NotBlank(message = "昵称不能为空")
|
||||
@Schema(description = "用户名", example = "张三")
|
||||
@NotBlank(message = "用户名不能为空")
|
||||
@Pattern(regexp = RegexConstants.GENERAL_NAME, message = "昵称长度为 2-30 个字符,支持中文、字母、数字、下划线,短横线")
|
||||
private String nickname;
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
|
||||
@@ -38,7 +38,6 @@ public class UserReq implements Serializable {
|
||||
@Pattern(regexp = RegexConstants.USERNAME, message = "用户名长度为 4-64 个字符,支持大小写字母、数字、下划线,以字母开头")
|
||||
private String username;
|
||||
|
||||
|
||||
/**
|
||||
* 密码(加密)
|
||||
*/
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package top.wms.admin.system.model.resp;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.common.model.resp.BaseDetailResp;
|
||||
import top.wms.admin.system.enums.NoticeScopeEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公告详情信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@Schema(description = "公告详情信息")
|
||||
public class NoticeDetailResp extends BaseDetailResp {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题", example = "这是公告标题")
|
||||
@ExcelProperty(value = "标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
@Schema(description = "内容", example = "这是公告内容")
|
||||
@ExcelProperty(value = "内容")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 类型(取值于字典 notice_type)
|
||||
*/
|
||||
@Schema(description = "类型(取值于字典 notice_type)", example = "1")
|
||||
@ExcelProperty(value = "类型")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 生效时间
|
||||
*/
|
||||
@Schema(description = "生效时间", example = "2023-08-08 00:00:00", type = "string")
|
||||
@ExcelProperty(value = "生效时间")
|
||||
private LocalDateTime effectiveTime;
|
||||
|
||||
/**
|
||||
* 终止时间
|
||||
*/
|
||||
@Schema(description = "终止时间", example = "2023-08-08 23:59:59", type = "string")
|
||||
@ExcelProperty(value = "终止时间")
|
||||
private LocalDateTime terminateTime;
|
||||
|
||||
/**
|
||||
* 通知范围
|
||||
*/
|
||||
@Schema(description = "通知范围", example = "2")
|
||||
private NoticeScopeEnum noticeScope;
|
||||
|
||||
/**
|
||||
* 指定用户
|
||||
*/
|
||||
@Schema(description = "指定用户", example = "[1,2,3]")
|
||||
private List<String> noticeUsers;
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package top.wms.admin.system.model.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.common.model.resp.BaseResp;
|
||||
import top.wms.admin.system.enums.NoticeScopeEnum;
|
||||
import top.wms.admin.system.enums.NoticeStatusEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公告信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "公告信息")
|
||||
public class NoticeResp extends BaseResp {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题", example = "这是公告标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 类型(取值于字典 notice_type)
|
||||
*/
|
||||
@Schema(description = "类型(取值于字典 notice_type)", example = "1")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 生效时间
|
||||
*/
|
||||
@Schema(description = "生效时间", example = "2023-08-08 00:00:00", type = "string")
|
||||
private LocalDateTime effectiveTime;
|
||||
|
||||
/**
|
||||
* 终止时间
|
||||
*/
|
||||
@Schema(description = "终止时间", example = "2023-08-08 23:59:59", type = "string")
|
||||
private LocalDateTime terminateTime;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* @return 公告状态
|
||||
*/
|
||||
@Schema(description = "状态", example = "1")
|
||||
public NoticeStatusEnum getStatus() {
|
||||
return NoticeStatusEnum.getStatus(effectiveTime, terminateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通知范围
|
||||
*/
|
||||
@Schema(description = "通知范围(1.所有人 2.指定用户)", example = "1")
|
||||
private NoticeScopeEnum noticeScope;
|
||||
|
||||
/**
|
||||
* 指定用户
|
||||
*/
|
||||
@Schema(description = "指定用户", example = "[1,2,3]")
|
||||
private List<String> noticeUsers;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package top.wms.admin.system.model.resp.dashboard;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 仪表盘-访问趋势信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/9/9 20:20
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "仪表盘-访问趋势信息")
|
||||
public class DashboardAccessTrendResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 日期
|
||||
*/
|
||||
@Schema(description = "日期", example = "2023-08-08")
|
||||
private String date;
|
||||
|
||||
/**
|
||||
* 浏览量(PV)
|
||||
*/
|
||||
@Schema(description = "浏览量(PV)", example = "1000")
|
||||
private Long pvCount;
|
||||
|
||||
/**
|
||||
* IP 数
|
||||
*/
|
||||
@Schema(description = "IP 数", example = "500")
|
||||
private Long ipCount;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package top.wms.admin.system.model.resp.dashboard;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 仪表盘-通用图表信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2024/10/17 21:37
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "仪表盘-通用图表信息")
|
||||
public class DashboardChartCommonResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
@Schema(description = "名称", example = "Windows 10")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
@Schema(description = "数量", example = "1234")
|
||||
private Long value;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package top.wms.admin.system.model.resp.dashboard;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 仪表盘-公告信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "仪表盘-公告信息")
|
||||
public class DashboardNoticeResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@Schema(description = "ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题", example = "这是公告标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 类型(取值于字典 notice_type)
|
||||
*/
|
||||
@Schema(description = "类型(取值于字典 notice_type)", example = "1")
|
||||
private String type;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package top.wms.admin.system.model.resp.dashboard;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 仪表盘-通用总览信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2024/10/19 12:19
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Schema(description = "仪表盘-通用总览信息")
|
||||
public class DashboardOverviewCommonResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
@Schema(description = "总数", example = "888888")
|
||||
private Long total;
|
||||
|
||||
/**
|
||||
* 今日数量
|
||||
*/
|
||||
@Schema(description = "今日数量", example = "888")
|
||||
private Long today;
|
||||
|
||||
/**
|
||||
* 较昨日新增(百分比)
|
||||
*/
|
||||
@Schema(description = "较昨日新增(百分比)", example = "23.4")
|
||||
private BigDecimal growth;
|
||||
|
||||
/**
|
||||
* 图表数据
|
||||
*/
|
||||
@Schema(description = "图表数据")
|
||||
private List<DashboardChartCommonResp> dataList;
|
||||
|
||||
/**
|
||||
* 昨日数量
|
||||
*/
|
||||
@JsonIgnore
|
||||
private Long yesterday;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package top.wms.admin.system.model.resp.dashboard;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 仪表盘-总计信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/9/8 21:32
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "仪表盘-总计信息")
|
||||
public class DashboardTotalResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 浏览量(PV)
|
||||
*/
|
||||
@Schema(description = "浏览量(PV)", example = "88888")
|
||||
private Long pvCount;
|
||||
|
||||
/**
|
||||
* IP 数
|
||||
*/
|
||||
@Schema(description = "IP 数", example = "66666")
|
||||
private Long ipCount;
|
||||
|
||||
/**
|
||||
* 今日浏览量(PV)
|
||||
*/
|
||||
@Schema(description = "今日浏览量(PV)", example = "1234")
|
||||
private Long todayPvCount;
|
||||
|
||||
/**
|
||||
* 较昨日新增 PV(百分比)
|
||||
*/
|
||||
@Schema(description = "较昨日新增(百分比)", example = "23.4")
|
||||
private BigDecimal newPvFromYesterday;
|
||||
|
||||
/**
|
||||
* 昨日浏览量(PV)
|
||||
*/
|
||||
@JsonIgnore
|
||||
private Long yesterdayPvCount;
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package top.wms.admin.system.model.resp.message;
|
||||
|
||||
import cn.crane4j.annotation.Assemble;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.common.constant.ContainerConstants;
|
||||
import top.wms.admin.system.enums.MessageTypeEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 消息信息
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "消息信息")
|
||||
public class MessageResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@Schema(description = "ID", example = "1")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题", example = "欢迎注册 xxx")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
@Schema(description = "内容", example = "尊敬的 xx,欢迎注册使用,请及时配置您的密码。")
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
@Schema(description = "类型(1:系统消息)", example = "1")
|
||||
private MessageTypeEnum type;
|
||||
|
||||
/**
|
||||
* 是否已读
|
||||
*/
|
||||
@Schema(description = "是否已读", example = "true")
|
||||
private Boolean isRead;
|
||||
|
||||
/**
|
||||
* 读取时间
|
||||
*/
|
||||
@Schema(description = "读取时间", example = "2023-08-08 23:59:59", type = "string")
|
||||
private LocalDateTime readTime;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@JsonIgnore
|
||||
@Assemble(prop = ":createUserString", container = ContainerConstants.USER_NICKNAME)
|
||||
private Long createUser;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@Schema(description = "创建人", example = "超级管理员")
|
||||
private String createUserString;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Schema(description = "创建时间", example = "2023-08-08 08:08:08", type = "string")
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package top.wms.admin.system.model.resp.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import top.wms.admin.system.enums.MessageTypeEnum;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 各类型未读消息信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/11/2 23:00
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "各类型未读消息信息")
|
||||
public class MessageTypeUnreadResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
@Schema(description = "类型(1:系统消息)", example = "1")
|
||||
private MessageTypeEnum type;
|
||||
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
@Schema(description = "数量", example = "10")
|
||||
private Long count;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package top.wms.admin.system.model.resp.message;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 未读消息信息
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/11/2 23:00
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "未读消息信息")
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
public class MessageUnreadResp implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 未读消息数量
|
||||
*/
|
||||
@Schema(description = "未读消息数量", example = "20")
|
||||
private Long total;
|
||||
|
||||
/**
|
||||
* 各类型未读消息数量
|
||||
*/
|
||||
@Schema(description = "各类型未读消息数量")
|
||||
private List<MessageTypeUnreadResp> details;
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
package top.wms.admin.system.model.resp.user;
|
||||
|
||||
import cn.crane4j.annotation.Assemble;
|
||||
import cn.crane4j.annotation.AssembleMethod;
|
||||
import cn.crane4j.annotation.ContainerMethod;
|
||||
import cn.crane4j.annotation.Mapping;
|
||||
import cn.crane4j.annotation.condition.ConditionOnExpression;
|
||||
import cn.crane4j.core.executor.handler.ManyToManyAssembleOperationHandler;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
@@ -15,8 +11,6 @@ import top.wms.admin.common.constant.ContainerConstants;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.common.enums.DisEnableStatusEnum;
|
||||
import top.wms.admin.common.enums.GenderEnum;
|
||||
import top.wms.admin.system.model.resp.DeptResp;
|
||||
import top.wms.admin.system.service.DeptService;
|
||||
import top.continew.starter.file.excel.converter.ExcelBaseEnumConverter;
|
||||
import top.continew.starter.file.excel.converter.ExcelListConverter;
|
||||
import top.continew.starter.security.crypto.annotation.FieldEncrypt;
|
||||
@@ -48,13 +42,6 @@ public class UserDetailResp extends BaseDetailResp {
|
||||
@ExcelProperty(value = "用户名", order = 2)
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
@Schema(description = "昵称", example = "张三")
|
||||
@ExcelProperty(value = "昵称", order = 3)
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@@ -69,22 +56,6 @@ public class UserDetailResp extends BaseDetailResp {
|
||||
@ExcelProperty(value = "性别", converter = ExcelBaseEnumConverter.class, order = 5)
|
||||
private GenderEnum gender;
|
||||
|
||||
/**
|
||||
* 部门 ID
|
||||
*/
|
||||
@Schema(description = "部门 ID", example = "5")
|
||||
@ConditionOnExpression("#target.deptName == null")
|
||||
@AssembleMethod(props = @Mapping(src = "name", ref = "deptName"), targetType = DeptService.class, method = @ContainerMethod(bindMethod = "get", resultType = DeptResp.class))
|
||||
@ExcelProperty(value = "部门 ID", order = 6)
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 所属部门
|
||||
*/
|
||||
@Schema(description = "所属部门", example = "测试部")
|
||||
@ExcelProperty(value = "所属部门", order = 7)
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 角色 ID 列表
|
||||
*/
|
||||
@@ -112,14 +83,6 @@ public class UserDetailResp extends BaseDetailResp {
|
||||
@ExcelProperty(value = "卡号", order = 11)
|
||||
private String cardNo;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Schema(description = "邮箱", example = "123456789@qq.com")
|
||||
@ExcelProperty(value = "邮箱", order = 12)
|
||||
@FieldEncrypt
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 是否为系统内置数据
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package top.wms.admin.system.model.resp.user;
|
||||
|
||||
import cn.crane4j.annotation.Assemble;
|
||||
import cn.crane4j.core.executor.handler.ManyToManyAssembleOperationHandler;
|
||||
import com.alibaba.excel.annotation.ExcelIgnore;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.Value;
|
||||
import top.wms.admin.common.model.resp.BaseDetailResp;
|
||||
import top.wms.admin.common.constant.ContainerConstants;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
@@ -40,18 +38,10 @@ public class UserResp extends BaseDetailResp {
|
||||
@ExcelProperty(value = "用户名")
|
||||
private String username;
|
||||
|
||||
|
||||
@Schema(description = "卡号")
|
||||
@ExcelProperty(value = "卡号")
|
||||
private String cardNo;
|
||||
|
||||
/**
|
||||
* 昵称
|
||||
*/
|
||||
@Schema(description = "昵称", example = "张三")
|
||||
@ExcelIgnore
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
@@ -65,14 +55,6 @@ public class UserResp extends BaseDetailResp {
|
||||
@ExcelIgnore
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
*/
|
||||
@Schema(description = "邮箱", example = "c*******@126.com")
|
||||
@JsonMask(MaskType.EMAIL)
|
||||
@ExcelIgnore
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 手机号码
|
||||
*/
|
||||
@@ -99,27 +81,6 @@ public class UserResp extends BaseDetailResp {
|
||||
@Schema(description = "描述", example = "张三描述信息")
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 部门 ID
|
||||
*/
|
||||
@Schema(description = "部门 ID", example = "5")
|
||||
@ExcelIgnore
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 所属部门
|
||||
*/
|
||||
@Schema(description = "所属部门", example = "测试部")
|
||||
@ExcelIgnore
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 角色 ID 列表
|
||||
*/
|
||||
@Schema(description = "角色 ID 列表", example = "2")
|
||||
@Assemble(prop = ":roleNames", container = ContainerConstants.USER_ROLE_NAME_LIST, handlerType = ManyToManyAssembleOperationHandler.class)
|
||||
private List<Long> roleIds;
|
||||
|
||||
/**
|
||||
* 角色名称列表
|
||||
*/
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
package top.wms.admin.system.service;
|
||||
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardAccessTrendResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardNoticeResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardOverviewCommonResp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 仪表盘业务接口
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/9/8 21:32
|
||||
*/
|
||||
public interface DashboardService {
|
||||
|
||||
/**
|
||||
* 查询公告列表
|
||||
*
|
||||
* @return 公告列表
|
||||
*/
|
||||
List<DashboardNoticeResp> listNotice();
|
||||
|
||||
/**
|
||||
* 查询 PV 总览
|
||||
*
|
||||
* @return PV 总览
|
||||
*/
|
||||
DashboardOverviewCommonResp getOverviewPv();
|
||||
|
||||
/**
|
||||
* 查询 IP 总览
|
||||
*
|
||||
* @return IP 总览
|
||||
*/
|
||||
DashboardOverviewCommonResp getOverviewIp();
|
||||
|
||||
/**
|
||||
* 查询地域分析信息
|
||||
*
|
||||
* @return 地域分析信息
|
||||
* @throws IOException /
|
||||
*/
|
||||
List<DashboardChartCommonResp> getAnalysisGeo() throws IOException;
|
||||
|
||||
/**
|
||||
* 查询访问趋势信息
|
||||
*
|
||||
* @param days 日期数
|
||||
* @return 访问趋势信息
|
||||
*/
|
||||
List<DashboardAccessTrendResp> listAccessTrend(Integer days);
|
||||
|
||||
/**
|
||||
* 查询访问时段分析信息
|
||||
*
|
||||
* @return 访问时段分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> getAnalysisTimeslot();
|
||||
|
||||
/**
|
||||
* 查询模块分析信息
|
||||
*
|
||||
* @return 模块分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> getAnalysisModule();
|
||||
|
||||
/**
|
||||
* 查询终端分析信息
|
||||
*
|
||||
* @return 终端分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> getAnalysisOs();
|
||||
|
||||
/**
|
||||
* 查询浏览器分析信息
|
||||
*
|
||||
* @return 浏览器分析信息
|
||||
*/
|
||||
List<DashboardChartCommonResp> getAnalysisBrowser();
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package top.wms.admin.system.service;
|
||||
|
||||
import top.wms.admin.system.model.query.MessageQuery;
|
||||
import top.wms.admin.system.model.req.MessageReq;
|
||||
import top.wms.admin.system.model.resp.message.MessageResp;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息业务接口
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
public interface MessageService {
|
||||
|
||||
/**
|
||||
* 分页查询列表
|
||||
*
|
||||
* @param query 查询条件
|
||||
* @param pageQuery 分页查询条件
|
||||
* @return 分页列表信息
|
||||
*/
|
||||
PageResp<MessageResp> page(MessageQuery query, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*
|
||||
* @param req 新增信息
|
||||
* @param userIdList 接收人列表
|
||||
*/
|
||||
void add(MessageReq req, List<Long> userIdList);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param ids ID 列表
|
||||
*/
|
||||
void delete(List<Long> ids);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package top.wms.admin.system.service;
|
||||
|
||||
import top.wms.admin.system.model.resp.message.MessageUnreadResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息和用户关联业务接口
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
public interface MessageUserService {
|
||||
|
||||
/**
|
||||
* 根据用户 ID 查询未读消息数量
|
||||
*
|
||||
* @param userId 用户 ID
|
||||
* @param isDetail 是否查询详情
|
||||
* @return 未读消息信息
|
||||
*/
|
||||
MessageUnreadResp countUnreadMessageByUserId(Long userId, Boolean isDetail);
|
||||
|
||||
/**
|
||||
* 新增
|
||||
*
|
||||
* @param messageId 消息 ID
|
||||
* @param userIdList 用户 ID 列表
|
||||
*/
|
||||
void add(Long messageId, List<Long> userIdList);
|
||||
|
||||
/**
|
||||
* 将消息标记已读
|
||||
*
|
||||
* @param ids 消息ID(为空则将所有消息标记已读)
|
||||
*/
|
||||
void readMessage(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 根据消息 ID 删除
|
||||
*
|
||||
* @param messageIds 消息 ID 列表
|
||||
*/
|
||||
void deleteByMessageIds(List<Long> messageIds);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package top.wms.admin.system.service;
|
||||
|
||||
import top.wms.admin.system.model.entity.NoticeDO;
|
||||
import top.wms.admin.system.model.query.NoticeQuery;
|
||||
import top.wms.admin.system.model.req.NoticeReq;
|
||||
import top.wms.admin.system.model.resp.NoticeDetailResp;
|
||||
import top.wms.admin.system.model.resp.NoticeResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardNoticeResp;
|
||||
import top.continew.starter.data.mp.service.IService;
|
||||
import top.continew.starter.extension.crud.service.BaseService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公告业务接口
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
public interface NoticeService extends BaseService<NoticeResp, NoticeDetailResp, NoticeQuery, NoticeReq>, IService<NoticeDO> {
|
||||
|
||||
/**
|
||||
* 查询仪表盘公告列表
|
||||
*
|
||||
* @return 仪表盘公告列表
|
||||
*/
|
||||
List<DashboardNoticeResp> listDashboard();
|
||||
}
|
||||
@@ -132,6 +132,14 @@ public interface UserService extends BaseService<UserResp, UserDetailResp, UserQ
|
||||
*/
|
||||
UserDO getByEmail(String email);
|
||||
|
||||
/**
|
||||
* 根据卡片查询
|
||||
*
|
||||
* @param card 卡片
|
||||
* @return 用户信息
|
||||
*/
|
||||
UserDO getByCard(String card);
|
||||
|
||||
/**
|
||||
* 根据部门 ID 列表查询
|
||||
*
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
package top.wms.admin.system.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DateField;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.wms.admin.system.mapper.LogMapper;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardAccessTrendResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardNoticeResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardOverviewCommonResp;
|
||||
import top.wms.admin.system.service.DashboardService;
|
||||
import top.wms.admin.system.service.NoticeService;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 仪表盘业务实现
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/9/8 21:32
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DashboardServiceImpl implements DashboardService {
|
||||
|
||||
private final LogMapper logMapper;
|
||||
private final NoticeService noticeService;
|
||||
|
||||
@Override
|
||||
public List<DashboardNoticeResp> listNotice() {
|
||||
return noticeService.listDashboard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DashboardOverviewCommonResp getOverviewPv() {
|
||||
DashboardOverviewCommonResp resp = logMapper.selectDashboardOverviewPv();
|
||||
resp.setGrowth(this.calcGrowthFromYesterday(resp.getToday(), resp.getYesterday()));
|
||||
List<String> last12MonthList = this.getLast12Months();
|
||||
List<DashboardChartCommonResp> dataList = logMapper.selectListDashboardAnalysisPv(last12MonthList);
|
||||
if (dataList.size() < 12) {
|
||||
// 填充缺失的数据
|
||||
this.fillMissingDateData(last12MonthList, dataList);
|
||||
}
|
||||
resp.setDataList(dataList);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DashboardOverviewCommonResp getOverviewIp() {
|
||||
DashboardOverviewCommonResp resp = logMapper.selectDashboardOverviewIp();
|
||||
resp.setGrowth(this.calcGrowthFromYesterday(resp.getToday(), resp.getYesterday()));
|
||||
List<String> last12MonthList = this.getLast12Months();
|
||||
List<DashboardChartCommonResp> dataList = logMapper.selectListDashboardAnalysisIp(last12MonthList);
|
||||
if (dataList.size() < 12) {
|
||||
// 填充缺失的数据
|
||||
this.fillMissingDateData(last12MonthList, dataList);
|
||||
}
|
||||
resp.setDataList(dataList);
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DashboardChartCommonResp> getAnalysisGeo() throws IOException {
|
||||
List<DashboardChartCommonResp> originList = logMapper.selectListDashboardAnalysisGeo();
|
||||
List<DashboardChartCommonResp> list = new ArrayList<>(34);
|
||||
// 获取省份数据
|
||||
String chinaJson = IoUtil.readUtf8(new ClassPathResource("china.json").getInputStream());
|
||||
JSONArray jsonArr = JSONUtil.parseObj(chinaJson).getJSONArray("children");
|
||||
List<String> provinceList = jsonArr.stream().map(item -> {
|
||||
JSONObject itemJsonObj = JSONUtil.parseObj(item);
|
||||
return "%s:%s".formatted(itemJsonObj.getStr("name"), itemJsonObj.getStr("fullname"));
|
||||
}).toList();
|
||||
// 汇总各省份访问数据
|
||||
for (String province : provinceList) {
|
||||
String[] split = province.split(StringConstants.COLON);
|
||||
String name = split[0];
|
||||
String fullName = split[1];
|
||||
long sum = originList.stream()
|
||||
.filter(item -> item.getName().contains(name))
|
||||
.mapToLong(DashboardChartCommonResp::getValue)
|
||||
.sum();
|
||||
list.add(new DashboardChartCommonResp(fullName, sum));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DashboardAccessTrendResp> listAccessTrend(Integer days) {
|
||||
DateTime currentDate = DateUtil.date();
|
||||
Date startTime = DateUtil.beginOfDay(DateUtil.offsetDay(currentDate, -days)).toJdkDate();
|
||||
Date endTime = DateUtil.endOfDay(DateUtil.offsetDay(currentDate, -1)).toJdkDate();
|
||||
List<DashboardAccessTrendResp> list = logMapper.selectListDashboardAccessTrend(startTime, endTime);
|
||||
if (list.size() < days) {
|
||||
List<String> all = DateUtil.rangeToList(startTime, endTime, DateField.DAY_OF_MONTH)
|
||||
.stream()
|
||||
.map(date -> date.toString(DatePattern.NORM_DATE_FORMAT))
|
||||
.toList();
|
||||
Collection<String> missings = CollUtil.disjunction(all, list.stream()
|
||||
.map(DashboardAccessTrendResp::getDate)
|
||||
.toList());
|
||||
list.addAll(missings.stream().map(missing -> new DashboardAccessTrendResp(missing, 0L, 0L)).toList());
|
||||
list.sort(Comparator.comparing(DashboardAccessTrendResp::getDate));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DashboardChartCommonResp> getAnalysisTimeslot() {
|
||||
List<DashboardChartCommonResp> list = logMapper.selectListDashboardAnalysisTimeslot();
|
||||
if (list.size() < 12) {
|
||||
// 获取所有时间段
|
||||
List<String> allTimeSlotList = new ArrayList<>(12);
|
||||
for (int hour = 0; hour < 24; hour += 2) {
|
||||
allTimeSlotList.add(String.format("%02d:00", hour));
|
||||
}
|
||||
// 填充缺失的数据
|
||||
this.fillMissingDateData(allTimeSlotList, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DashboardChartCommonResp> getAnalysisModule() {
|
||||
return logMapper.selectListDashboardAnalysisModule(10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DashboardChartCommonResp> getAnalysisOs() {
|
||||
List<DashboardChartCommonResp> list = logMapper.selectListDashboardAnalysisOs(4);
|
||||
return this.buildOtherPieChartData(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DashboardChartCommonResp> getAnalysisBrowser() {
|
||||
List<DashboardChartCommonResp> list = logMapper.selectListDashboardAnalysisBrowser(4);
|
||||
return this.buildOtherPieChartData(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算增长百分比
|
||||
*
|
||||
* @param today 今日数量
|
||||
* @param yesterday 昨日数量
|
||||
* @return 增长百分比
|
||||
*/
|
||||
private BigDecimal calcGrowthFromYesterday(Long today, Long yesterday) {
|
||||
return (0 == yesterday)
|
||||
? BigDecimal.valueOf(100)
|
||||
: NumberUtil.round(NumberUtil.mul(NumberUtil.div(NumberUtil.sub(today, yesterday), yesterday), 100), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建其他饼图数据
|
||||
*
|
||||
* @param list 饼图数据列表
|
||||
* @return 饼图数据列表
|
||||
*/
|
||||
private List<DashboardChartCommonResp> buildOtherPieChartData(List<DashboardChartCommonResp> list) {
|
||||
Long totalCount = logMapper.selectTotalCount();
|
||||
long sumCount = list.stream().mapToLong(DashboardChartCommonResp::getValue).sum();
|
||||
if (sumCount < totalCount) {
|
||||
list.add(new DashboardChartCommonResp("其他", totalCount - sumCount));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充缺失时间段的数据
|
||||
*
|
||||
* @param all 所有时间段
|
||||
* @param list 待填充数据
|
||||
*/
|
||||
private void fillMissingDateData(List<String> all, List<DashboardChartCommonResp> list) {
|
||||
Collection<String> missings = CollUtil.disjunction(all, list.stream()
|
||||
.map(DashboardChartCommonResp::getName)
|
||||
.toList());
|
||||
list.addAll(missings.stream().map(missing -> new DashboardChartCommonResp(missing, 0L)).toList());
|
||||
list.sort(Comparator.comparing(DashboardChartCommonResp::getName));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近12个月的月份列表
|
||||
*
|
||||
* @return 月份列表
|
||||
*/
|
||||
private List<String> getLast12Months() {
|
||||
DateTime currentMonth = DateUtil.beginOfMonth(DateUtil.date());
|
||||
return DateUtil.rangeToList(DateUtil.offsetMonth(currentMonth, -12), DateUtil
|
||||
.offsetMonth(currentMonth, -1), DateField.MONTH)
|
||||
.stream()
|
||||
.map(dateTime -> DateUtil.format(dateTime, DatePattern.NORM_MONTH_FORMAT))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,6 @@ import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 部门业务实现
|
||||
@@ -87,17 +86,7 @@ public class DeptServiceImpl extends BaseServiceImpl<DeptMapper, DeptDO, DeptRes
|
||||
|
||||
@Override
|
||||
public void beforeDelete(List<Long> ids) {
|
||||
List<DeptDO> list = baseMapper.lambdaQuery()
|
||||
.select(DeptDO::getName, DeptDO::getIsSystem)
|
||||
.in(DeptDO::getId, ids)
|
||||
.list();
|
||||
Optional<DeptDO> isSystemData = list.stream().filter(DeptDO::getIsSystem).findFirst();
|
||||
CheckUtils.throwIf(isSystemData::isPresent, "所选部门 [{}] 是系统内置部门,不允许删除", isSystemData.orElseGet(DeptDO::new)
|
||||
.getName());
|
||||
CheckUtils.throwIf(this.countChildren(ids) > 0, "所选部门存在下级部门,不允许删除");
|
||||
CheckUtils.throwIf(userService.countByDeptIds(ids) > 0, "所选部门存在用户关联,请解除关联后重试");
|
||||
// 删除角色和部门关联
|
||||
roleDeptService.deleteByDeptIds(ids);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -100,13 +100,18 @@ public class FileServiceImpl extends BaseServiceImpl<FileMapper, FileDO, FileRes
|
||||
}
|
||||
});
|
||||
// 处理本地存储文件 URL
|
||||
FileInfo fileInfo = uploadPretreatment.upload();
|
||||
String domain = StrUtil.appendIfMissing(storage.getDomain(), StringConstants.SLASH);
|
||||
fileInfo.setUrl(URLUtil.normalize(domain + fileInfo.getPath() + fileInfo.getFilename()));
|
||||
if (StrUtil.isNotBlank(fileInfo.getThFilename())) {
|
||||
fileInfo.setThUrl(URLUtil.normalize(domain + fileInfo.getPath() + fileInfo.getThFilename()));
|
||||
} else {
|
||||
fileInfo.setThUrl(fileInfo.getUrl());
|
||||
FileInfo fileInfo = null;
|
||||
try {
|
||||
fileInfo = uploadPretreatment.upload();
|
||||
String domain = StrUtil.appendIfMissing(storage.getDomain(), StringConstants.SLASH);
|
||||
fileInfo.setUrl(URLUtil.normalize(domain + fileInfo.getPath() + fileInfo.getFilename()));
|
||||
if (StrUtil.isNotBlank(fileInfo.getThFilename())) {
|
||||
fileInfo.setThUrl(URLUtil.normalize(domain + fileInfo.getPath() + fileInfo.getThFilename()));
|
||||
} else {
|
||||
fileInfo.setThUrl(fileInfo.getUrl());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
return fileInfo;
|
||||
}
|
||||
@@ -146,4 +151,4 @@ public class FileServiceImpl extends BaseServiceImpl<FileMapper, FileDO, FileRes
|
||||
fileResp.setStorageName("%s (%s)".formatted(storage.getName(), storage.getCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package top.wms.admin.system.service.impl;
|
||||
|
||||
import cn.crane4j.annotation.AutoOperate;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import top.wms.admin.system.mapper.MessageMapper;
|
||||
import top.wms.admin.system.model.entity.MessageDO;
|
||||
import top.wms.admin.system.model.query.MessageQuery;
|
||||
import top.wms.admin.system.model.req.MessageReq;
|
||||
import top.wms.admin.system.model.resp.message.MessageResp;
|
||||
import top.wms.admin.system.service.MessageService;
|
||||
import top.wms.admin.system.service.MessageUserService;
|
||||
import top.continew.starter.core.validation.CheckUtils;
|
||||
import top.continew.starter.data.mp.util.QueryWrapperHelper;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息业务实现
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MessageServiceImpl implements MessageService {
|
||||
|
||||
private final MessageMapper baseMapper;
|
||||
private final MessageUserService messageUserService;
|
||||
|
||||
@Override
|
||||
@AutoOperate(type = MessageResp.class, on = "list")
|
||||
public PageResp<MessageResp> page(MessageQuery query, PageQuery pageQuery) {
|
||||
QueryWrapper<MessageDO> queryWrapper = QueryWrapperHelper.build(query, pageQuery.getSort());
|
||||
queryWrapper.apply(null != query.getUserId(), "t2.user_id={0}", query.getUserId())
|
||||
.apply(null != query.getIsRead(), "t2.is_read={0}", query.getIsRead());
|
||||
IPage<MessageResp> page = baseMapper.selectPageByUserId(new Page<>(pageQuery.getPage(), pageQuery
|
||||
.getSize()), queryWrapper);
|
||||
return PageResp.build(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void add(MessageReq req, List<Long> userIdList) {
|
||||
CheckUtils.throwIf(() -> CollUtil.isEmpty(userIdList), "消息接收人不能为空");
|
||||
MessageDO message = BeanUtil.copyProperties(req, MessageDO.class);
|
||||
baseMapper.insert(message);
|
||||
messageUserService.add(message.getId(), userIdList);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(List<Long> ids) {
|
||||
baseMapper.deleteByIds(ids);
|
||||
messageUserService.deleteByMessageIds(ids);
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package top.wms.admin.system.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.wms.admin.system.enums.MessageTypeEnum;
|
||||
import top.wms.admin.system.mapper.MessageUserMapper;
|
||||
import top.wms.admin.system.model.entity.MessageUserDO;
|
||||
import top.wms.admin.system.model.resp.message.MessageTypeUnreadResp;
|
||||
import top.wms.admin.system.model.resp.message.MessageUnreadResp;
|
||||
import top.wms.admin.system.service.MessageUserService;
|
||||
import top.continew.starter.core.validation.CheckUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息和用户关联业务实现
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MessageUserServiceImpl implements MessageUserService {
|
||||
|
||||
private final MessageUserMapper baseMapper;
|
||||
|
||||
@Override
|
||||
public MessageUnreadResp countUnreadMessageByUserId(Long userId, Boolean isDetail) {
|
||||
MessageUnreadResp result = new MessageUnreadResp();
|
||||
Long total = 0L;
|
||||
if (Boolean.TRUE.equals(isDetail)) {
|
||||
List<MessageTypeUnreadResp> detailList = new ArrayList<>();
|
||||
for (MessageTypeEnum messageType : MessageTypeEnum.values()) {
|
||||
MessageTypeUnreadResp resp = new MessageTypeUnreadResp();
|
||||
resp.setType(messageType);
|
||||
Long count = baseMapper.selectUnreadCountByUserIdAndType(userId, messageType.getValue());
|
||||
resp.setCount(count);
|
||||
detailList.add(resp);
|
||||
total += count;
|
||||
}
|
||||
result.setDetails(detailList);
|
||||
} else {
|
||||
total = baseMapper.selectUnreadCountByUserIdAndType(userId, null);
|
||||
}
|
||||
result.setTotal(total);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Long messageId, List<Long> userIdList) {
|
||||
CheckUtils.throwIfEmpty(userIdList, "消息接收人不能为空");
|
||||
List<MessageUserDO> messageUserList = userIdList.stream().map(userId -> {
|
||||
MessageUserDO messageUser = new MessageUserDO();
|
||||
messageUser.setUserId(userId);
|
||||
messageUser.setMessageId(messageId);
|
||||
messageUser.setIsRead(false);
|
||||
return messageUser;
|
||||
}).toList();
|
||||
baseMapper.insert(messageUserList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMessage(List<Long> ids) {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return;
|
||||
}
|
||||
baseMapper.lambdaUpdate()
|
||||
.set(MessageUserDO::getIsRead, true)
|
||||
.set(MessageUserDO::getReadTime, LocalDateTime.now())
|
||||
.eq(MessageUserDO::getIsRead, false)
|
||||
.in(CollUtil.isNotEmpty(ids), MessageUserDO::getMessageId, ids)
|
||||
.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByMessageIds(List<Long> messageIds) {
|
||||
if (CollUtil.isEmpty(messageIds)) {
|
||||
return;
|
||||
}
|
||||
baseMapper.lambdaUpdate().in(MessageUserDO::getMessageId, messageIds).remove();
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package top.wms.admin.system.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.system.mapper.NoticeMapper;
|
||||
import top.wms.admin.system.model.entity.NoticeDO;
|
||||
import top.wms.admin.system.model.query.NoticeQuery;
|
||||
import top.wms.admin.system.model.req.NoticeReq;
|
||||
import top.wms.admin.system.model.resp.NoticeDetailResp;
|
||||
import top.wms.admin.system.model.resp.NoticeResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardNoticeResp;
|
||||
import top.wms.admin.system.service.NoticeService;
|
||||
import top.continew.starter.extension.crud.service.BaseServiceImpl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 公告业务实现
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class NoticeServiceImpl extends BaseServiceImpl<NoticeMapper, NoticeDO, NoticeResp, NoticeDetailResp, NoticeQuery, NoticeReq> implements NoticeService {
|
||||
|
||||
@Override
|
||||
public List<DashboardNoticeResp> listDashboard() {
|
||||
Long userId = UserContextHolder.isAdmin() ? null : UserContextHolder.getUserId();
|
||||
return baseMapper.selectDashboardList(userId);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package top.wms.admin.system.service.impl;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import top.continew.starter.extension.crud.service.BaseServiceImpl;
|
||||
import top.wms.admin.system.mapper.PeopleEquipmentMapper;
|
||||
import top.wms.admin.system.model.entity.PeopleEquipmentDO;
|
||||
import top.wms.admin.system.model.query.PeopleEquipmentQuery;
|
||||
import top.wms.admin.system.model.req.PeopleEquipmentReq;
|
||||
import top.wms.admin.system.model.resp.PeopleEquipmentResp;
|
||||
import top.wms.admin.system.service.PeopleEquipmentService;
|
||||
|
||||
/**
|
||||
* 人员设备下发信息业务实现
|
||||
*
|
||||
* @author zc
|
||||
* @since 2025/03/27 14:59
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PeopleEquipmentServiceImpl extends BaseServiceImpl<PeopleEquipmentMapper, PeopleEquipmentDO, PeopleEquipmentResp, PeopleEquipmentResp, PeopleEquipmentQuery, PeopleEquipmentReq> implements PeopleEquipmentService {}
|
||||
@@ -36,6 +36,7 @@ import net.dreamlu.mica.core.result.R;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.dromara.x.file.storage.core.FileStorageService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -131,6 +132,8 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(email) && this.isEmailExists(email, null), errorMsgTemplate, email);
|
||||
String phone = req.getPhone();
|
||||
CheckUtils.throwIf(StrUtil.isNotBlank(phone) && this.isPhoneExists(phone, null), errorMsgTemplate, phone);
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
req.setPassword("{bcrypt}" + encoder.encode(req.getPassword()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -158,10 +161,10 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
UserDO oldUser = super.getById(id);
|
||||
if (Boolean.TRUE.equals(oldUser.getIsSystem())) {
|
||||
CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, newStatus, "[{}] 是系统内置用户,不允许禁用", oldUser
|
||||
.getNickname());
|
||||
.getUsername());
|
||||
Collection<Long> disjunctionRoleIds = CollUtil.disjunction(req.getRoleIds(), userRoleService
|
||||
.listRoleIdByUserId(id));
|
||||
CheckUtils.throwIfNotEmpty(disjunctionRoleIds, "[{}] 是系统内置用户,不允许变更角色", oldUser.getNickname());
|
||||
CheckUtils.throwIfNotEmpty(disjunctionRoleIds, "[{}] 是系统内置用户,不允许变更角色", oldUser.getUsername());
|
||||
}
|
||||
// 更新信息
|
||||
UserDO newUser = BeanUtil.toBean(req, UserDO.class);
|
||||
@@ -186,12 +189,12 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
public void delete(List<Long> ids) {
|
||||
CheckUtils.throwIf(CollUtil.contains(ids, UserContextHolder.getUserId()), "不允许删除当前用户");
|
||||
List<UserDO> list = baseMapper.lambdaQuery()
|
||||
.select(UserDO::getNickname, UserDO::getIsSystem)
|
||||
.select(UserDO::getUsername, UserDO::getIsSystem)
|
||||
.in(UserDO::getId, ids)
|
||||
.list();
|
||||
Optional<UserDO> isSystemData = list.stream().filter(UserDO::getIsSystem).findFirst();
|
||||
CheckUtils.throwIf(isSystemData::isPresent, "所选用户 [{}] 是系统内置用户,不允许删除", isSystemData.orElseGet(UserDO::new)
|
||||
.getNickname());
|
||||
.getUsername());
|
||||
// 删除用户和角色关联
|
||||
userRoleService.deleteByUserIds(ids);
|
||||
// 删除历史密码
|
||||
@@ -335,7 +338,6 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
userDO.setStatus(req.getDefaultStatus());
|
||||
userDO.setPwdResetTime(LocalDateTime.now());
|
||||
userDO.setGender(EnumUtil.getBy(GenderEnum::getDescription, row.getGender(), GenderEnum.UNKNOWN));
|
||||
userDO.setDeptId(deptMap.get(row.getDeptName()));
|
||||
// 修改 or 新增
|
||||
if (UPDATE.validate(req.getDuplicateUser(), row.getUsername(), existUsernames)) {
|
||||
userDO.setId(userMap.get(row.getUsername()));
|
||||
@@ -396,7 +398,7 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
public void updateBasicInfo(UserBasicInfoUpdateReq req, Long id) {
|
||||
super.getById(id);
|
||||
baseMapper.lambdaUpdate()
|
||||
.set(UserDO::getNickname, req.getNickname())
|
||||
.set(UserDO::getUsername, req.getUserName())
|
||||
.set(UserDO::getGender, req.getGender())
|
||||
.eq(UserDO::getId, id)
|
||||
.update();
|
||||
@@ -460,12 +462,14 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
return baseMapper.selectByEmail(email);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDO getByCard(String card) {
|
||||
return baseMapper.selectByCard(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long countByDeptIds(List<Long> deptIds) {
|
||||
if (CollUtil.isEmpty(deptIds)) {
|
||||
return 0L;
|
||||
}
|
||||
return baseMapper.lambdaQuery().in(UserDO::getDeptId, deptIds).count();
|
||||
return 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -737,6 +741,4 @@ public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserDO, UserRes
|
||||
return null == userDO ? "" : userDO.getUsername();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package top.wms.admin.weighManage.mapper;
|
||||
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import top.wms.admin.weighManage.model.entity.WorkOrderInfoDO;
|
||||
|
||||
/**
|
||||
* 任务工单详情 Mapper
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/04 14:16
|
||||
*/
|
||||
@Repository
|
||||
public interface WorkOrderInfoMapper extends BaseMapper<WorkOrderInfoDO> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package top.wms.admin.weighManage.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import top.continew.starter.data.mp.base.BaseMapper;
|
||||
import top.wms.admin.weighManage.model.entity.WorkOrderDO;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import top.wms.admin.weighManage.model.resp.WorkOrderInfoResp;
|
||||
import top.wms.admin.weighManage.model.resp.WorkOrderResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务工单信息 Mapper
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/03 17:09
|
||||
*/
|
||||
@Repository
|
||||
public interface WorkOrderMapper extends BaseMapper<WorkOrderDO> {
|
||||
|
||||
/**
|
||||
* 获取任务工单分页列表
|
||||
*
|
||||
* @param objectPage 分页参数
|
||||
* @param queryWrapper 查询参数
|
||||
* @return 任务工单分页列表
|
||||
*/
|
||||
IPage<WorkOrderResp> selectWorkOrderPage(@Param("page") Page<Object> objectPage,
|
||||
@Param(Constants.WRAPPER) QueryWrapper<WorkOrderDO> queryWrapper);
|
||||
|
||||
/**
|
||||
* 获取任务工单详情信息
|
||||
*
|
||||
* @param id 任务工单主键id
|
||||
* @return 任务工单详情信息
|
||||
*/
|
||||
List<WorkOrderInfoResp> getDetail(Long id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package top.wms.admin.weighManage.model.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import top.wms.admin.common.model.entity.BaseDO;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 任务工单信息实体
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/03 17:09
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_work_order")
|
||||
public class WorkOrderDO extends BaseDO {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 任务工单号
|
||||
*/
|
||||
private String orderNo;
|
||||
|
||||
/**
|
||||
* 物料主键id
|
||||
*/
|
||||
private Long materialId;
|
||||
|
||||
/**
|
||||
* 总重量
|
||||
*/
|
||||
private BigDecimal totalWeight;
|
||||
|
||||
/**
|
||||
* 总数量
|
||||
*/
|
||||
private Integer totalCount;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package top.wms.admin.weighManage.model.entity;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import top.wms.admin.common.model.entity.BaseDO;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 任务工单详情实体
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/04 14:16
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_work_order_info")
|
||||
public class WorkOrderInfoDO extends BaseDO {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 工单主键id
|
||||
*/
|
||||
private Long workOrderId;
|
||||
|
||||
/**
|
||||
* 物料主键id
|
||||
*/
|
||||
private Long materialId;
|
||||
|
||||
/**
|
||||
* 称重次数
|
||||
*/
|
||||
private int weightTime;
|
||||
|
||||
/**
|
||||
* 抓拍的图片
|
||||
*/
|
||||
private String imgUrl;
|
||||
|
||||
/**
|
||||
* 物料数量
|
||||
*/
|
||||
private BigDecimal quantity;
|
||||
|
||||
/**
|
||||
* 称重重量
|
||||
*/
|
||||
private BigDecimal weight;
|
||||
|
||||
/**
|
||||
* 计算重量
|
||||
*/
|
||||
private BigDecimal calculatedWeight;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package top.wms.admin.weighManage.model.query;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.*;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 任务工单信息查询条件
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/03 17:09
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "任务工单信息查询条件")
|
||||
public class WorkOrderQuery implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 任务工单号
|
||||
*/
|
||||
@Schema(description = "任务工单号")
|
||||
private String orderNo;
|
||||
|
||||
/**
|
||||
* 物料名称
|
||||
*/
|
||||
@Schema(description = "物料名称")
|
||||
private String materialName;
|
||||
|
||||
/**
|
||||
* 物料编码
|
||||
*/
|
||||
@Schema(description = "物料编码")
|
||||
private String encoding;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@Schema(description = "创建人")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 卡号
|
||||
*/
|
||||
@Schema(description = "卡号")
|
||||
private String carNo;
|
||||
|
||||
/**
|
||||
* 创建开始时间
|
||||
*/
|
||||
@Schema(description = "创建开始时间")
|
||||
private Date startTime;
|
||||
|
||||
/**
|
||||
* 创建结束时间
|
||||
*/
|
||||
@Schema(description = "创建结束时间")
|
||||
private Date endTime;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package top.wms.admin.weighManage.model.req;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
/**
|
||||
* 创建或修改任务工单信息参数
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/03 17:09
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "创建或修改任务工单信息参数")
|
||||
public class WorkOrderInfoReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 工单主键id
|
||||
*/
|
||||
@Schema(description = "工单主键id")
|
||||
private Long workOrderId;
|
||||
|
||||
/**
|
||||
* 物料主键id
|
||||
*/
|
||||
@Schema(description = "物料主键id")
|
||||
@NotNull(message = "物料主键id不能为空")
|
||||
private Long materialId;
|
||||
|
||||
/**
|
||||
* 称重次数
|
||||
*/
|
||||
@Schema(description = "称重次数")
|
||||
private Integer weightTime;
|
||||
|
||||
/**
|
||||
* 物料数量
|
||||
*/
|
||||
@Schema(description = "物料数量")
|
||||
private Integer quantity;
|
||||
|
||||
/**
|
||||
* 称重重量
|
||||
*/
|
||||
@Schema(description = "称重重量")
|
||||
private BigDecimal weight;
|
||||
|
||||
/**
|
||||
* 计算重量
|
||||
*/
|
||||
@Schema(description = "计算重量")
|
||||
private BigDecimal calculatedWeight;
|
||||
|
||||
/**
|
||||
* 抓拍的图片
|
||||
*/
|
||||
@Schema(description = "抓拍的图片")
|
||||
private String imgUrl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package top.wms.admin.weighManage.model.req;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 创建或修改任务工单信息参数
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/03 17:09
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "创建或修改任务工单信息参数")
|
||||
public class WorkOrderReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 物料主键id
|
||||
*/
|
||||
@Schema(description = "物料主键id")
|
||||
@NotNull(message = "物料主键id不能为空")
|
||||
private Long materialId;
|
||||
|
||||
/**
|
||||
* 物料名称
|
||||
*/
|
||||
@Schema(description = "物料名称")
|
||||
@NotBlank(message = "物料名称不能为空")
|
||||
private String materialName;
|
||||
|
||||
/**
|
||||
* 称重列表
|
||||
*/
|
||||
@Schema(description = "称重列表")
|
||||
@NotEmpty(message = "称重列表不能为空")
|
||||
private List<WorkOrderInfoReq> workOrderInfos;
|
||||
|
||||
/**
|
||||
* 手动填写的物料数量
|
||||
*/
|
||||
private String inputQuantity;
|
||||
|
||||
/**
|
||||
* 电子秤重量
|
||||
*/
|
||||
private String ahDeviceWeight;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package top.wms.admin.weighManage.model.resp;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 任务工单详情信息
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/04 14:21
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "任务工单详情信息")
|
||||
public class WorkOrderInfoResp {
|
||||
|
||||
/**
|
||||
* 主键id
|
||||
*/
|
||||
@Schema(description = "主键id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 工单主键id
|
||||
*/
|
||||
@Schema(description = "工单主键id")
|
||||
private Long workOrderId;
|
||||
|
||||
/**
|
||||
* 物料主键id
|
||||
*/
|
||||
@Schema(description = "物料主键id")
|
||||
private Long materialId;
|
||||
|
||||
/**
|
||||
* 物料主键id
|
||||
*/
|
||||
@Schema(description = "物料主键id")
|
||||
private String materialName;
|
||||
|
||||
/**
|
||||
* 称重次数
|
||||
*/
|
||||
@Schema(description = "称重次数")
|
||||
private int weightTime;
|
||||
|
||||
/**
|
||||
* 物料数量
|
||||
*/
|
||||
@Schema(description = "物料数量")
|
||||
private BigDecimal quantity;
|
||||
|
||||
/**
|
||||
* 称重重量
|
||||
*/
|
||||
@Schema(description = "称重重量")
|
||||
private BigDecimal weight;
|
||||
|
||||
/**
|
||||
* 计算重量
|
||||
*/
|
||||
@Schema(description = "计算重量")
|
||||
private BigDecimal calculatedWeight;
|
||||
|
||||
/**
|
||||
* 抓拍的图片
|
||||
*/
|
||||
@Schema(description = "抓拍的图片")
|
||||
private String imgUrl;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package top.wms.admin.weighManage.model.resp;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import top.wms.admin.common.model.resp.BaseDetailResp;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.time.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务工单信息信息
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/03 17:09
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "任务工单信息信息")
|
||||
public class WorkOrderResp extends BaseDetailResp {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 卡号
|
||||
*/
|
||||
@Schema(description = "卡号")
|
||||
private String cardNo;
|
||||
|
||||
/**
|
||||
* 工单编号
|
||||
*/
|
||||
@Schema(description = "工单编号")
|
||||
private String orderNo;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
@Schema(description = "标题")
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 物料主键id
|
||||
*/
|
||||
@Schema(description = "物料主键id")
|
||||
private Long materialId;
|
||||
|
||||
/**
|
||||
* 物料名称
|
||||
*/
|
||||
@Schema(description = "物料名称")
|
||||
private String materialName;
|
||||
|
||||
/**
|
||||
* 物料编码
|
||||
*/
|
||||
@Schema(description = "物料编码")
|
||||
private String encoding;
|
||||
|
||||
/**
|
||||
* 物料单位重量
|
||||
*/
|
||||
@Schema(description = "物料单位重量")
|
||||
private BigDecimal unitWeight;
|
||||
|
||||
/**
|
||||
* 物料规格
|
||||
*/
|
||||
@Schema(description = "物料规格")
|
||||
private String materialSpec;
|
||||
|
||||
/**
|
||||
* 物料图片
|
||||
*/
|
||||
@Schema(description = "物料图片")
|
||||
private String photoUrl;
|
||||
|
||||
/**
|
||||
* 计算总重量(标重)
|
||||
*/
|
||||
@Schema(description = "计算总重量(标重)")
|
||||
private BigDecimal totalCalculatedWeight;
|
||||
|
||||
/**
|
||||
* 实际总重量
|
||||
*/
|
||||
@Schema(description = "实际总重量")
|
||||
private BigDecimal totalWeight;
|
||||
|
||||
/**
|
||||
* 总数量
|
||||
*/
|
||||
@Schema(description = "总数量")
|
||||
private int totalCount;
|
||||
|
||||
/**
|
||||
* 任务工单详情信息列表
|
||||
*/
|
||||
@Schema(description = "任务工单详情信息列表")
|
||||
private List<WorkOrderInfoResp> workOrderInfos;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package top.wms.admin.weighManage.service;
|
||||
|
||||
import top.continew.starter.extension.crud.service.BaseService;
|
||||
import top.wms.admin.weighManage.model.query.WorkOrderQuery;
|
||||
import top.wms.admin.weighManage.model.req.WorkOrderReq;
|
||||
import top.wms.admin.weighManage.model.resp.WorkOrderInfoResp;
|
||||
import top.wms.admin.weighManage.model.resp.WorkOrderResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务工单信息业务接口
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/03 17:09
|
||||
*/
|
||||
public interface WorkOrderService extends BaseService<WorkOrderResp, WorkOrderResp, WorkOrderQuery, WorkOrderReq> {
|
||||
|
||||
/**
|
||||
* 获取任务工单详情信息
|
||||
*
|
||||
* @param id 任务工单主键id
|
||||
* @return 任务工单详情信息
|
||||
*/
|
||||
WorkOrderResp getDetail(Long id);
|
||||
|
||||
/**
|
||||
* 创建任务工单
|
||||
*
|
||||
* @param req 创建任务工单参数
|
||||
* @return 任务工单信息
|
||||
*/
|
||||
WorkOrderResp addWorKerOrder(WorkOrderReq req);
|
||||
|
||||
/**
|
||||
* 获取任务工单详情信息
|
||||
*
|
||||
* @param id 任务工单主键id
|
||||
* @return 任务工单详情信息
|
||||
*/
|
||||
List<WorkOrderInfoResp> getWorkOrderInfos(Long id);
|
||||
|
||||
/**
|
||||
* 校验物料数量和重量是否匹配
|
||||
*
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
int validateWeighing(WorkOrderReq req);
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package top.wms.admin.weighManage.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
import top.continew.starter.extension.crud.service.BaseServiceImpl;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.material.mapper.MaterialInfoMapper;
|
||||
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
||||
import top.wms.admin.system.service.ConfigService;
|
||||
import top.wms.admin.weighManage.mapper.WorkOrderInfoMapper;
|
||||
import top.wms.admin.weighManage.mapper.WorkOrderMapper;
|
||||
import top.wms.admin.weighManage.model.entity.WorkOrderDO;
|
||||
import top.wms.admin.weighManage.model.entity.WorkOrderInfoDO;
|
||||
import top.wms.admin.weighManage.model.query.WorkOrderQuery;
|
||||
import top.wms.admin.weighManage.model.req.WorkOrderInfoReq;
|
||||
import top.wms.admin.weighManage.model.req.WorkOrderReq;
|
||||
import top.wms.admin.weighManage.model.resp.WorkOrderInfoResp;
|
||||
import top.wms.admin.weighManage.model.resp.WorkOrderResp;
|
||||
import top.wms.admin.weighManage.service.WorkOrderService;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 任务工单信息业务实现
|
||||
*
|
||||
* @author zc
|
||||
* @since 2026/03/03 17:09
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class WorkOrderServiceImpl extends BaseServiceImpl<WorkOrderMapper, WorkOrderDO, WorkOrderResp, WorkOrderResp, WorkOrderQuery, WorkOrderReq> implements WorkOrderService {
|
||||
|
||||
private final WorkOrderInfoMapper workOrderInfoMapper;
|
||||
|
||||
private final MaterialInfoMapper materialInfoMapper;
|
||||
|
||||
private final ConfigService configService;
|
||||
|
||||
@Override
|
||||
public PageResp<WorkOrderResp> page(WorkOrderQuery query, PageQuery pageQuery) {
|
||||
QueryWrapper<WorkOrderDO> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.like(StrUtil.isNotBlank(query.getMaterialName()), "m.material_name", query.getMaterialName());
|
||||
queryWrapper.eq(null != query.getOrderNo(), "w.order_no", query.getOrderNo());
|
||||
this.sort(queryWrapper, pageQuery);
|
||||
|
||||
IPage<WorkOrderResp> page = baseMapper.selectWorkOrderPage(new Page<>(pageQuery.getPage(), pageQuery
|
||||
.getSize()), queryWrapper);
|
||||
|
||||
return PageResp.build(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkOrderResp getDetail(Long id) {
|
||||
WorkOrderDO workOrderDO = baseMapper.selectById(id);
|
||||
WorkOrderResp workOrderResp = BeanUtil.copyProperties(workOrderDO, WorkOrderResp.class);
|
||||
if (null != workOrderDO.getMaterialId()) {
|
||||
MaterialInfoDO materialInfoDO = materialInfoMapper.selectById(workOrderDO.getMaterialId());
|
||||
workOrderResp.setMaterialName(materialInfoDO.getMaterialName());
|
||||
workOrderResp.setEncoding(materialInfoDO.getEncoding());
|
||||
}
|
||||
|
||||
List<WorkOrderInfoDO> workOrderInfos = workOrderInfoMapper.selectList(new QueryWrapper<WorkOrderInfoDO>()
|
||||
.eq("work_order_id", id));
|
||||
if (CollUtil.isNotEmpty(workOrderInfos)) {
|
||||
BigDecimal bigDecimal = new BigDecimal("0");
|
||||
for (WorkOrderInfoDO workOrderInfoDO : workOrderInfos) {
|
||||
bigDecimal = bigDecimal.add(workOrderInfoDO.getCalculatedWeight());
|
||||
}
|
||||
workOrderResp.setTotalCalculatedWeight(bigDecimal);
|
||||
}
|
||||
|
||||
return workOrderResp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkOrderInfoResp> getWorkOrderInfos(Long id) {
|
||||
return baseMapper.getDetail(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterDelete(List<Long> ids) {
|
||||
workOrderInfoMapper.delete(new QueryWrapper<WorkOrderInfoDO>().in("work_order_id", ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkOrderResp addWorKerOrder(WorkOrderReq req) {
|
||||
if (CollUtil.isEmpty(req.getWorkOrderInfos())) {
|
||||
throw new IllegalArgumentException("称重列表不能为空");
|
||||
}
|
||||
|
||||
BigDecimal totalWeight = new BigDecimal("0");
|
||||
int totalCount = 0;
|
||||
for (WorkOrderInfoReq workOrderInfoReq : req.getWorkOrderInfos()) {
|
||||
totalWeight = workOrderInfoReq.getWeight().add(totalWeight);
|
||||
totalCount += workOrderInfoReq.getQuantity();
|
||||
}
|
||||
|
||||
WorkOrderDO workOrder = new WorkOrderDO();
|
||||
// 生成纯数字订单号:年月日时分秒 + 6位随机数
|
||||
String timestamp = DateUtil.format(new Date(), "yyyyMMddHHmmss");
|
||||
String randomNum = String.format("%06d", (int)(Math.random() * 1000000));
|
||||
workOrder.setOrderNo(timestamp + randomNum);
|
||||
String title = DateUtil.format(new Date(), DatePattern.CHINESE_DATE_PATTERN) + "-" + UserContextHolder
|
||||
.getUsername() + "-" + req.getMaterialName();
|
||||
workOrder.setTitle(title);
|
||||
workOrder.setMaterialId(req.getMaterialId());
|
||||
workOrder.setTotalWeight(totalWeight);
|
||||
workOrder.setTotalCount(totalCount);
|
||||
baseMapper.insert(workOrder);
|
||||
|
||||
//新增工单详情列表信息
|
||||
List<WorkOrderInfoDO> workOrderInfoDOList = BeanUtil.copyToList(req.getWorkOrderInfos(), WorkOrderInfoDO.class);
|
||||
workOrderInfoDOList.forEach(workOrderInfoDO -> workOrderInfoDO.setWorkOrderId(workOrder.getId()));
|
||||
workOrderInfoMapper.insertBatch(workOrderInfoDOList);
|
||||
|
||||
return BeanUtil.copyProperties(workOrder, WorkOrderResp.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int validateWeighing(WorkOrderReq req) {
|
||||
log.info("validateWeighing req:{}", req);
|
||||
String configValue = configService.getConfigValue("weight_float_ratio");
|
||||
BigDecimal weightFloat = new BigDecimal("0.06");
|
||||
if (StrUtil.isNotBlank(configValue)) {
|
||||
weightFloat = new BigDecimal(configValue);
|
||||
}
|
||||
|
||||
//计算标准重量
|
||||
MaterialInfoDO materialInfoDO = materialInfoMapper.selectById(req.getMaterialId());
|
||||
BigDecimal standardWeight = materialInfoDO.getUnitWeight().subtract(new BigDecimal(req.getInputQuantity()));
|
||||
BigDecimal electronicWeight = new BigDecimal(req.getAhDeviceWeight());
|
||||
|
||||
// 检查 electronicWeight 是否大于 standardWeight
|
||||
if (electronicWeight.compareTo(standardWeight) <= 0) {
|
||||
log.error("电子秤重量必须大于标准重量");
|
||||
return 500; // 电子秤重量必须大于标准重量
|
||||
}
|
||||
|
||||
// 计算比值:(electronicWeight - standardWeight) / standardWeight
|
||||
BigDecimal weightDifference = electronicWeight.subtract(standardWeight);
|
||||
BigDecimal ratio = weightDifference.divide(standardWeight, 4, BigDecimal.ROUND_HALF_UP);
|
||||
|
||||
// 检查比值是否超过 6%
|
||||
if (ratio.compareTo(weightFloat) > 0) {
|
||||
log.error("比值超过 6%,当前比值: {}", ratio);
|
||||
return 500; // 比值超过 6%
|
||||
}
|
||||
|
||||
return 200; // 验证通过
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,115 +41,4 @@
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
<select id="selectDashboardOverviewPv" resultType="top.wms.admin.system.model.resp.dashboard.DashboardOverviewCommonResp">
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM sys_log) AS total,
|
||||
(SELECT COUNT(*) FROM sys_log WHERE create_time >= CURDATE() AND create_time < DATE_ADD(CURDATE(), INTERVAL 1 DAY)) AS today,
|
||||
(SELECT COUNT(*) FROM sys_log WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND create_time < CURDATE()) AS yesterday
|
||||
</select>
|
||||
|
||||
<select id="selectDashboardOverviewIp" resultType="top.wms.admin.system.model.resp.dashboard.DashboardOverviewCommonResp">
|
||||
SELECT
|
||||
(SELECT COUNT(DISTINCT ip) FROM sys_log) AS total,
|
||||
(SELECT COUNT(DISTINCT ip) FROM sys_log WHERE create_time >= CURDATE() AND create_time < DATE_ADD(CURDATE(), INTERVAL 1 DAY)) AS today,
|
||||
(SELECT COUNT(DISTINCT ip) FROM sys_log WHERE create_time >= DATE_SUB(CURDATE(), INTERVAL 1 DAY) AND create_time < CURDATE()) AS yesterday
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardAnalysisPv"
|
||||
resultType="top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp">
|
||||
SELECT
|
||||
DATE_FORMAT(create_time, '%Y-%m') AS name,
|
||||
COUNT(*) AS value
|
||||
FROM sys_log
|
||||
WHERE DATE_FORMAT(create_time, '%Y-%m' ) IN
|
||||
<foreach collection="months" item="month" separator="," open="(" close=")">
|
||||
#{month}
|
||||
</foreach>
|
||||
GROUP BY name
|
||||
ORDER BY name
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardAnalysisIp"
|
||||
resultType="top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp">
|
||||
SELECT
|
||||
DATE_FORMAT(create_time, '%Y-%m') AS name,
|
||||
COUNT(DISTINCT ip) AS value
|
||||
FROM sys_log
|
||||
WHERE DATE_FORMAT(create_time, '%Y-%m' ) IN
|
||||
<foreach collection="months" item="month" separator="," open="(" close=")">
|
||||
#{month}
|
||||
</foreach>
|
||||
GROUP BY name
|
||||
ORDER BY name
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardAnalysisGeo" resultType="top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp">
|
||||
SELECT
|
||||
CASE
|
||||
WHEN POSITION(' ' IN address) > 0 THEN SUBSTRING(address FROM 1 FOR POSITION(' ' IN address) - 1)
|
||||
ELSE address
|
||||
END AS name,
|
||||
COUNT(*) AS value
|
||||
FROM sys_log
|
||||
WHERE address LIKE '中国%'
|
||||
GROUP BY name
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardAccessTrend"
|
||||
resultType="top.wms.admin.system.model.resp.dashboard.DashboardAccessTrendResp">
|
||||
SELECT
|
||||
DATE(create_time) AS date,
|
||||
COUNT(*) AS pvCount,
|
||||
COUNT(DISTINCT ip) AS ipCount
|
||||
FROM sys_log
|
||||
WHERE create_time BETWEEN #{startTime} AND #{endTime}
|
||||
GROUP BY date
|
||||
ORDER BY date
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardAnalysisTimeslot"
|
||||
resultType="top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp">
|
||||
SELECT
|
||||
LPAD(CONCAT(FLOOR(HOUR(create_time) / 2) * 2, ':00'), 5, '0') AS name,
|
||||
COUNT(*) AS value
|
||||
FROM sys_log
|
||||
GROUP BY name
|
||||
ORDER BY name
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardAnalysisModule"
|
||||
resultType="top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp">
|
||||
SELECT
|
||||
module AS name,
|
||||
COUNT(*) AS value
|
||||
FROM sys_log
|
||||
WHERE module != '验证码' AND module != '登录'
|
||||
GROUP BY name
|
||||
ORDER BY value DESC
|
||||
LIMIT #{top}
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardAnalysisOs"
|
||||
resultType="top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp">
|
||||
SELECT
|
||||
os AS name,
|
||||
COUNT(*) AS value
|
||||
FROM sys_log
|
||||
WHERE os IS NOT NULL
|
||||
GROUP BY name
|
||||
ORDER BY value DESC
|
||||
LIMIT #{top}
|
||||
</select>
|
||||
|
||||
<select id="selectListDashboardAnalysisBrowser"
|
||||
resultType="top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp">
|
||||
SELECT
|
||||
SUBSTRING_INDEX(browser, ' ', 1) AS name,
|
||||
COUNT(*) AS value
|
||||
FROM sys_log
|
||||
WHERE browser IS NOT NULL
|
||||
GROUP BY name
|
||||
ORDER BY value DESC
|
||||
LIMIT #{top}
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.wms.admin.system.mapper.MessageMapper">
|
||||
<select id="selectPageByUserId" resultType="top.wms.admin.system.model.resp.message.MessageResp">
|
||||
SELECT
|
||||
t1.*,
|
||||
t2.user_id,
|
||||
t2.is_read,
|
||||
t2.read_time
|
||||
FROM sys_message AS t1
|
||||
LEFT JOIN sys_message_user AS t2 ON t2.message_id = t1.id
|
||||
${ew.getCustomSqlSegment}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.wms.admin.system.mapper.MessageUserMapper">
|
||||
<select id="selectUnreadCountByUserIdAndType" resultType="Long">
|
||||
SELECT
|
||||
COUNT(t1.message_id)
|
||||
FROM sys_message_user AS t1
|
||||
LEFT JOIN sys_message AS t2 ON t2.id = t1.message_id
|
||||
WHERE t1.user_id = #{userId} AND t1.is_read = false
|
||||
<if test="type != null">
|
||||
AND t2.type = #{type}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -1,4 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.wms.admin.material.mapper.MaterialInfoMapper">
|
||||
|
||||
<!-- 按物料名称批量更新 -->
|
||||
<update id="updateByName">
|
||||
<foreach collection="list" item="item" separator=";">
|
||||
UPDATE sys_material_info
|
||||
SET
|
||||
<if test="item.encoding != null and item.encoding != ''" >
|
||||
encoding = #{item.encoding},
|
||||
</if>
|
||||
<if test="item.unitWeight != null">
|
||||
unit_weight = #{item.unitWeight},
|
||||
</if>
|
||||
<if test="item.materialSpec != null and item.materialSpec != ''">
|
||||
material_spec = #{item.materialSpec},
|
||||
</if>
|
||||
<if test="item.updateTime != null">
|
||||
update_time = NOW(),
|
||||
</if>
|
||||
<if test="item.updateUser != null and item.updateUser != ''">
|
||||
update_user = #{item.updateUser}
|
||||
</if>
|
||||
WHERE material_name = #{item.materialName}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<update id="updateByCode">
|
||||
<foreach collection="list" item="item" separator=";">
|
||||
UPDATE sys_material_info
|
||||
SET
|
||||
<if test="item.materialName != null and item.materialName != ''">
|
||||
material_name = #{item.materialName},
|
||||
</if>
|
||||
<if test="item.unitWeight != null">
|
||||
unit_weight = #{item.unitWeight},
|
||||
</if>
|
||||
<if test="item.materialSpec != null and item.materialSpec != ''">
|
||||
material_spec = #{item.materialSpec},
|
||||
</if>
|
||||
<if test="item.updateTime != null">
|
||||
update_time = NOW(),
|
||||
</if>
|
||||
<if test="item.updateUser != null and item.updateUser != ''">
|
||||
update_user = #{item.updateUser}
|
||||
</if>
|
||||
WHERE encoding = #{item.encoding}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.wms.admin.system.mapper.NoticeMapper">
|
||||
|
||||
<select id="selectDashboardList"
|
||||
resultType="top.wms.admin.system.model.resp.dashboard.DashboardNoticeResp">
|
||||
SELECT
|
||||
id, title, type
|
||||
FROM sys_notice
|
||||
WHERE (effective_time IS NULL OR NOW() > effective_time)
|
||||
AND (terminate_time IS NULL OR terminate_time > NOW())
|
||||
<if test="userId != null">
|
||||
AND (notice_scope = 1 OR (notice_scope = 2 AND JSON_EXTRACT(notice_users, "$[0]") = CAST(#{userId} AS CHAR)))
|
||||
</if>
|
||||
ORDER BY sort ASC, effective_time DESC
|
||||
LIMIT 5
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.wms.admin.system.mapper.RuleRelationMapper">
|
||||
|
||||
|
||||
<delete id="deleteByRuleId" parameterType="top.wms.admin.system.model.entity.RuleRelationDO">
|
||||
DELETE FROM equipment_rule_relation
|
||||
WHERE 1=1
|
||||
<!-- 判空规则:字段不为 null 且 不为空字符串(兼容字符串/数字类型) -->
|
||||
<if test="ruleId != null and ruleId != ''">
|
||||
AND rule_id = #{ruleId}
|
||||
</if>
|
||||
<if test="equipmentId != null and equipmentId != ''">
|
||||
AND equipment_id = #{equipmentId}
|
||||
</if>
|
||||
<if test="equipmentRuleId != null and equipmentRuleId != ''">
|
||||
AND equipment_rule_id = #{equipmentRuleId}
|
||||
</if>
|
||||
</delete>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="top.wms.admin.weighManage.mapper.WorkOrderMapper">
|
||||
|
||||
<select id="selectWorkOrderPage" resultType="top.wms.admin.weighManage.model.resp.WorkOrderResp">
|
||||
select
|
||||
w.*,
|
||||
m.material_name,
|
||||
m.encoding,
|
||||
m.photo_url,
|
||||
m.unit_weight,
|
||||
u.card_no,
|
||||
u.username createUserString
|
||||
from sys_work_order w
|
||||
left join sys_material_info m on w.material_id = m.id
|
||||
left join sys_user u on w.create_user = u.id
|
||||
${ew.customSqlSegment}
|
||||
</select>
|
||||
|
||||
<select id="getDetail" resultType="top.wms.admin.weighManage.model.resp.WorkOrderInfoResp">
|
||||
select
|
||||
wi.*,
|
||||
m.material_name
|
||||
from sys_work_order_info wi
|
||||
left join sys_material_info m on wi.material_id = m.id
|
||||
where wi.work_order_id = #{id}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -53,6 +53,23 @@
|
||||
<artifactId>aws-java-sdk-s3</artifactId>
|
||||
<version>1.12.780</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fazecast</groupId>
|
||||
<artifactId>jSerialComm</artifactId>
|
||||
<version>2.9.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.websocket</groupId>
|
||||
<artifactId>jakarta.websocket-api</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.hikvision</groupId>
|
||||
<artifactId>MvCameraControlWrapper</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/Library/MvCameraControlWrapper.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<finalName>${project.parent.name}</finalName>
|
||||
|
||||
50
wms-webapi/Library/JavaEnv.bat
Normal file
50
wms-webapi/Library/JavaEnv.bat
Normal file
@@ -0,0 +1,50 @@
|
||||
:: 检查java安装环境
|
||||
|
||||
@echo off
|
||||
|
||||
:: 设置全局错误码
|
||||
set /A errorcode=0
|
||||
|
||||
:: 开启扩展功能
|
||||
setlocal ENABLEEXTENSIONS
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
|
||||
::通过向临时文件写内容,判断是否有文件读写权限
|
||||
echo > tmp
|
||||
if exist tmp (
|
||||
del /F/Q tmp >nul 2>&1
|
||||
) else (
|
||||
echo Please switch to an administrator account to run this batch!!!
|
||||
set /A errorcode=1
|
||||
goto:END
|
||||
)
|
||||
|
||||
::判断JAVA_HOME是否被定义
|
||||
if "%JAVA_HOME%"=="" (
|
||||
echo JAVA_HOME not set. Please make sure that java is correctly installed.
|
||||
set /A errorcode=2
|
||||
goto:END
|
||||
)
|
||||
|
||||
:: 判断CLASSPATH是否被定义
|
||||
if "%CLASSPATH%"=="" (
|
||||
echo CLASSPATH not set. Please make sure that java is correctly installed.
|
||||
set /A errorcode=3
|
||||
goto:END
|
||||
)
|
||||
|
||||
:: 判断java版本是否比 1.7.0高,需先将版本信息重定向到文件中,再对文件内容进行分析
|
||||
java -version >nul 2> JavaVer.tmp
|
||||
for /F "tokens=1,2,3*" %%i in (JavaVer.tmp) do (
|
||||
if "%%j" == "version" (
|
||||
if %%k LSS "1.7.0" (
|
||||
echo Java version is less than "1.7.0", warnings or errors may occur.
|
||||
)
|
||||
)
|
||||
)
|
||||
del /F/Q JavaVer.tmp >nul 2>&1
|
||||
|
||||
:END
|
||||
|
||||
::返回错误码
|
||||
exit /B %errorcode%
|
||||
BIN
wms-webapi/Library/MvCameraControlWrapper.jar
Normal file
BIN
wms-webapi/Library/MvCameraControlWrapper.jar
Normal file
Binary file not shown.
@@ -67,6 +67,28 @@
|
||||
<artifactId>aws-java-sdk-s3</artifactId>
|
||||
<version>1.12.780</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fazecast</groupId>
|
||||
<artifactId>jSerialComm</artifactId>
|
||||
<version>2.9.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- WebSocket API -->
|
||||
<dependency>
|
||||
<groupId>jakarta.websocket</groupId>
|
||||
<artifactId>jakarta.websocket-api</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 本地库:MvCameraControlWrapper -->
|
||||
<dependency>
|
||||
<groupId>com.hikvision</groupId>
|
||||
<artifactId>MvCameraControlWrapper</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/Library/MvCameraControlWrapper.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.x.file.storage.spring.EnableFileStorage;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.continew.starter.core.autoconfigure.project.ProjectProperties;
|
||||
@@ -29,6 +30,7 @@ import top.continew.starter.web.model.R;
|
||||
@RestController
|
||||
@SpringBootApplication
|
||||
@RequiredArgsConstructor
|
||||
@EnableScheduling
|
||||
public class WmsAdminApplication {
|
||||
|
||||
private final ProjectProperties projectProperties;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package top.wms.admin.config.satoken;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.interceptor.SaInterceptor;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package top.wms.admin.config.webSocket;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||
import top.wms.admin.controller.weighManage.ah.ScaleWebSocketHandler;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocket
|
||||
public class WebSocketConfig implements WebSocketConfigurer {
|
||||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
// 注册WebSocket端点,允许所有跨域请求
|
||||
registry.addHandler(new ScaleWebSocketHandler(), "/ws/scale").setAllowedOrigins("*");
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package top.wms.admin.controller.common;
|
||||
|
||||
import com.alicp.jetcache.anno.CachePenetrationProtect;
|
||||
import com.alicp.jetcache.anno.CacheRefresh;
|
||||
import com.alicp.jetcache.anno.CacheType;
|
||||
import com.alicp.jetcache.anno.Cached;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.constant.CacheConstants;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardAccessTrendResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardChartCommonResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardNoticeResp;
|
||||
import top.wms.admin.system.model.resp.dashboard.DashboardOverviewCommonResp;
|
||||
import top.wms.admin.system.service.DashboardService;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 仪表盘 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/1/22 21:48
|
||||
*/
|
||||
@Tag(name = "仪表盘 API")
|
||||
@Log(ignore = true)
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/dashboard")
|
||||
public class DashboardController {
|
||||
|
||||
private final DashboardService dashboardService;
|
||||
|
||||
@Operation(summary = "查询公告列表", description = "查询公告列表")
|
||||
@GetMapping("/notice")
|
||||
public List<DashboardNoticeResp> listNotice() {
|
||||
return dashboardService.listNotice();
|
||||
}
|
||||
|
||||
@Operation(summary = "查询PV总览", description = "查询PV总览")
|
||||
@GetMapping("/analysis/overview/pv")
|
||||
public DashboardOverviewCommonResp getOverviewPv() {
|
||||
return dashboardService.getOverviewPv();
|
||||
}
|
||||
|
||||
@Operation(summary = "查询IP总览", description = "查询IP总览")
|
||||
@GetMapping("/analysis/overview/ip")
|
||||
public DashboardOverviewCommonResp getOverviewIp() {
|
||||
return dashboardService.getOverviewIp();
|
||||
}
|
||||
|
||||
@Operation(summary = "查询地域分析", description = "查询地域分析")
|
||||
@GetMapping("/analysis/geo")
|
||||
@CachePenetrationProtect
|
||||
@CacheRefresh(refresh = 7200)
|
||||
@Cached(key = "'GEO'", name = CacheConstants.DASHBOARD_KEY_PREFIX, cacheType = CacheType.BOTH, syncLocal = true)
|
||||
public List<DashboardChartCommonResp> getAnalysisGeo() throws IOException {
|
||||
return dashboardService.getAnalysisGeo();
|
||||
}
|
||||
|
||||
@Operation(summary = "查询访问趋势信息", description = "查询访问趋势信息")
|
||||
@Parameter(name = "days", description = "日期数", example = "30", in = ParameterIn.PATH)
|
||||
@GetMapping("/access/trend/{days}")
|
||||
@CachePenetrationProtect
|
||||
@CacheRefresh(refresh = 7200)
|
||||
@Cached(key = "#days", name = CacheConstants.DASHBOARD_KEY_PREFIX, cacheType = CacheType.BOTH, syncLocal = true)
|
||||
public List<DashboardAccessTrendResp> listAccessTrend(@PathVariable Integer days) {
|
||||
ValidationUtils.throwIf(7 != days && 30 != days, "仅支持查询近 7/30 天访问趋势信息");
|
||||
return dashboardService.listAccessTrend(days);
|
||||
}
|
||||
|
||||
@Operation(summary = "查询访问时段分析", description = "查询访问时段分析")
|
||||
@GetMapping("/analysis/timeslot")
|
||||
@CachePenetrationProtect
|
||||
@CacheRefresh(refresh = 7200)
|
||||
@Cached(key = "'TIMESLOT'", name = CacheConstants.DASHBOARD_KEY_PREFIX, cacheType = CacheType.BOTH, syncLocal = true)
|
||||
public List<DashboardChartCommonResp> getAnalysisTimeslot() {
|
||||
return dashboardService.getAnalysisTimeslot();
|
||||
}
|
||||
|
||||
@Operation(summary = "查询模块分析", description = "查询模块分析")
|
||||
@GetMapping("/analysis/module")
|
||||
@CachePenetrationProtect
|
||||
@CacheRefresh(refresh = 7200)
|
||||
@Cached(key = "'MODULE'", name = CacheConstants.DASHBOARD_KEY_PREFIX, cacheType = CacheType.BOTH, syncLocal = true)
|
||||
public List<DashboardChartCommonResp> getAnalysisModule() {
|
||||
return dashboardService.getAnalysisModule();
|
||||
}
|
||||
|
||||
@Operation(summary = "查询终端分析", description = "查询终端分析")
|
||||
@GetMapping("/analysis/os")
|
||||
@CachePenetrationProtect
|
||||
@CacheRefresh(refresh = 7200)
|
||||
@Cached(key = "'OS'", name = CacheConstants.DASHBOARD_KEY_PREFIX, cacheType = CacheType.BOTH, syncLocal = true)
|
||||
public List<DashboardChartCommonResp> getAnalysisOs() {
|
||||
return dashboardService.getAnalysisOs();
|
||||
}
|
||||
|
||||
@Operation(summary = "查询浏览器分析", description = "查询浏览器分析")
|
||||
@GetMapping("/analysis/browser")
|
||||
@CachePenetrationProtect
|
||||
@CacheRefresh(refresh = 7200)
|
||||
@Cached(key = "'BROWSER'", name = CacheConstants.DASHBOARD_KEY_PREFIX, cacheType = CacheType.BOTH, syncLocal = true)
|
||||
public List<DashboardChartCommonResp> getAnalysisBrowser() {
|
||||
return dashboardService.getAnalysisBrowser();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,14 @@
|
||||
package top.wms.admin.controller.meterial;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import top.continew.starter.core.validation.CheckUtils;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@@ -8,12 +17,19 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.web.model.R;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.material.model.entity.MaterialInfoDO;
|
||||
import top.wms.admin.material.model.query.MaterialInfoQuery;
|
||||
import top.wms.admin.material.model.req.MaterialInfoImportReq;
|
||||
import top.wms.admin.material.model.req.MaterialInfoReq;
|
||||
import top.wms.admin.material.model.resp.MaterialImportParseResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoImportResp;
|
||||
import top.wms.admin.material.model.resp.MaterialInfoResp;
|
||||
import top.wms.admin.material.service.MaterialInfoService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 物料信息管理 API
|
||||
*
|
||||
@@ -23,7 +39,54 @@ import top.wms.admin.material.service.MaterialInfoService;
|
||||
@Tag(name = "物料信息管理 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@CrudRequestMapping(value = "/admin/meterialInfo", api = {Api.PAGE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE, Api.EXPORT})
|
||||
@CrudRequestMapping(value = "/admin/materialInfo", api = {Api.PAGE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE,
|
||||
Api.EXPORT})
|
||||
public class MaterialInfoController extends BaseController<MaterialInfoService, MaterialInfoResp, MaterialInfoResp, MaterialInfoQuery, MaterialInfoReq> {
|
||||
|
||||
@GetMapping("/code/{code}")
|
||||
public MaterialInfoDO getMaterialInfoByCode(@PathVariable String code) {
|
||||
MaterialInfoDO materialInfoDO = baseService.getMaterialInfoByCode(code);
|
||||
CheckUtils.throwIfEmpty(materialInfoDO, "未查询到相关物料信息");
|
||||
return materialInfoDO;
|
||||
}
|
||||
|
||||
@Operation(summary = "下载导入模板", description = "下载导入模板")
|
||||
@SaCheckPermission("admin:materialInfo:import")
|
||||
@GetMapping(value = "/import/template", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||
public void downloadImportTemplate(HttpServletResponse response) throws IOException {
|
||||
baseService.downloadImportTemplate(response);
|
||||
}
|
||||
|
||||
@Operation(summary = "解析导入数据", description = "解析导入数据")
|
||||
@SaCheckPermission("admin:materialInfo:import")
|
||||
@PostMapping("/import/parse")
|
||||
public MaterialImportParseResp parseImport(@NotNull(message = "文件不能为空") MultipartFile file) {
|
||||
ValidationUtils.throwIf(file::isEmpty, "文件不能为空");
|
||||
return baseService.parseImport(file);
|
||||
}
|
||||
|
||||
@Operation(summary = "导入数据", description = "导入数据")
|
||||
@SaCheckPermission("admin:materialInfo:import")
|
||||
@PostMapping(value = "/import")
|
||||
public MaterialInfoImportResp importUser(@Validated @RequestBody MaterialInfoImportReq req) {
|
||||
return baseService.importMaterial(req);
|
||||
}
|
||||
|
||||
@Operation(summary = "照片批量导入", description = "照片批量导入")
|
||||
@SaCheckPermission("admin:materialInfo:import")
|
||||
@PostMapping("/import/uploadMaterialPhotos")
|
||||
public R uploadMaterialPhotos(@RequestParam("zipFile") @NotNull(message = "文件不能为空") MultipartFile zipFile) {
|
||||
ValidationUtils.throwIf(zipFile::isEmpty, "文件不能为空");
|
||||
String originalFilename = zipFile.getOriginalFilename();
|
||||
ValidationUtils.throwIf(() -> originalFilename == null || !originalFilename.endsWith(".zip"), "仅支持上传ZIP格式文件");
|
||||
baseService.uploadMaterialPhotos(zipFile);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "照片抓取", description = "照片抓取")
|
||||
@PostMapping("/import/catch")
|
||||
public String catchPhoto(@RequestParam("file") MultipartFile file) {
|
||||
CheckUtils.throwIfEmpty(file, "照片抓取失败,请重新抓取");
|
||||
return baseService.catchPhoto(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,6 @@ public class DemoEnvironmentJob {
|
||||
private final DictItemMapper dictItemMapper;
|
||||
private final DictMapper dictMapper;
|
||||
private final StorageMapper storageMapper;
|
||||
private final NoticeMapper noticeMapper;
|
||||
private final MessageMapper messageMapper;
|
||||
private final MessageUserMapper messageUserMapper;
|
||||
private final UserMapper userMapper;
|
||||
private final UserRoleMapper userRoleMapper;
|
||||
private final UserSocialMapper userSocialMapper;
|
||||
@@ -67,10 +64,6 @@ public class DemoEnvironmentJob {
|
||||
this.log(dictCount, "字典");
|
||||
Long storageCount = storageMapper.lambdaQuery().gt(StorageDO::getId, DELETE_FLAG).count();
|
||||
this.log(storageCount, "存储");
|
||||
Long noticeCount = noticeMapper.lambdaQuery().gt(NoticeDO::getId, DELETE_FLAG).count();
|
||||
this.log(noticeCount, "公告");
|
||||
Long messageCount = messageMapper.lambdaQuery().count();
|
||||
this.log(messageCount, "通知");
|
||||
Long userCount = userMapper.lambdaQuery().notIn(UserDO::getId, USER_FLAG).count();
|
||||
this.log(userCount, "用户");
|
||||
Long roleCount = roleMapper.lambdaQuery().notIn(RoleDO::getId, ROLE_FLAG).count();
|
||||
@@ -83,8 +76,6 @@ public class DemoEnvironmentJob {
|
||||
this.log(clientCount, "终端");
|
||||
InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().blockAttack(true).build());
|
||||
SnailJobLog.REMOTE.info("演示环境待清理数据项检测完成,开始执行清理。");
|
||||
// 清理关联数据
|
||||
messageUserMapper.lambdaUpdate().gt(MessageUserDO::getMessageId, MESSAGE_FLAG).remove();
|
||||
userRoleMapper.lambdaUpdate().notIn(UserRoleDO::getRoleId, ROLE_FLAG).remove();
|
||||
userRoleMapper.lambdaUpdate().notIn(UserRoleDO::getUserId, USER_FLAG).remove();
|
||||
roleDeptMapper.lambdaUpdate().notIn(RoleDeptDO::getRoleId, ROLE_FLAG).remove();
|
||||
@@ -100,12 +91,6 @@ public class DemoEnvironmentJob {
|
||||
this.clean(storageCount, "存储", null, () -> storageMapper.lambdaUpdate()
|
||||
.gt(StorageDO::getId, DELETE_FLAG)
|
||||
.remove());
|
||||
this.clean(noticeCount, "公告", null, () -> noticeMapper.lambdaUpdate()
|
||||
.gt(NoticeDO::getId, DELETE_FLAG)
|
||||
.remove());
|
||||
this.clean(messageCount, "通知", null, () -> messageMapper.lambdaUpdate()
|
||||
.gt(MessageDO::getId, MESSAGE_FLAG)
|
||||
.remove());
|
||||
this.clean(userCount, "用户", null, () -> userMapper.lambdaUpdate().notIn(UserDO::getId, USER_FLAG).remove());
|
||||
this.clean(roleCount, "角色", null, () -> roleMapper.lambdaUpdate().notIn(RoleDO::getId, ROLE_FLAG).remove());
|
||||
this.clean(menuCount, "菜单", CacheConstants.ROLE_MENU_KEY_PREFIX, () -> menuMapper.lambdaUpdate()
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.enums.ParameterIn;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import top.wms.admin.common.context.UserContextHolder;
|
||||
import top.wms.admin.system.model.query.MessageQuery;
|
||||
import top.wms.admin.system.model.resp.message.MessageResp;
|
||||
import top.wms.admin.system.model.resp.message.MessageUnreadResp;
|
||||
import top.wms.admin.system.service.MessageService;
|
||||
import top.wms.admin.system.service.MessageUserService;
|
||||
import top.continew.starter.extension.crud.model.query.PageQuery;
|
||||
import top.continew.starter.extension.crud.model.resp.PageResp;
|
||||
import top.continew.starter.log.annotation.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 消息管理 API
|
||||
*
|
||||
* @author Bull-BCLS
|
||||
* @since 2023/10/15 19:05
|
||||
*/
|
||||
@Tag(name = "消息管理 API")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/system/message")
|
||||
public class MessageController {
|
||||
|
||||
private final MessageService baseService;
|
||||
private final MessageUserService messageUserService;
|
||||
|
||||
@Operation(summary = "分页查询列表", description = "分页查询列表")
|
||||
@GetMapping
|
||||
public PageResp<MessageResp> page(MessageQuery query, @Validated PageQuery pageQuery) {
|
||||
query.setUserId(UserContextHolder.getUserId());
|
||||
return baseService.page(query, pageQuery);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除数据", description = "删除数据")
|
||||
@Parameter(name = "ids", description = "ID 列表", example = "1,2", in = ParameterIn.PATH)
|
||||
@DeleteMapping("/{ids}")
|
||||
public void delete(@PathVariable List<Long> ids) {
|
||||
baseService.delete(ids);
|
||||
}
|
||||
|
||||
@Operation(summary = "标记已读", description = "将消息标记为已读状态")
|
||||
@Parameter(name = "ids", description = "消息ID列表", example = "1,2", in = ParameterIn.QUERY)
|
||||
@PatchMapping("/read")
|
||||
public void readMessage(@RequestParam(required = false) List<Long> ids) {
|
||||
messageUserService.readMessage(ids);
|
||||
}
|
||||
|
||||
@Log(ignore = true)
|
||||
@Operation(summary = "查询未读消息数量", description = "查询当前用户的未读消息数量")
|
||||
@Parameter(name = "isDetail", description = "是否查询详情", example = "true", in = ParameterIn.QUERY)
|
||||
@GetMapping("/unread")
|
||||
public MessageUnreadResp countUnreadMessage(@RequestParam(required = false) Boolean detail) {
|
||||
return messageUserService.countUnreadMessageByUserId(UserContextHolder.getUserId(), detail);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package top.wms.admin.controller.system;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import top.wms.admin.common.controller.BaseController;
|
||||
import top.wms.admin.system.enums.NoticeScopeEnum;
|
||||
import top.wms.admin.system.model.query.NoticeQuery;
|
||||
import top.wms.admin.system.model.req.NoticeReq;
|
||||
import top.wms.admin.system.model.resp.NoticeDetailResp;
|
||||
import top.wms.admin.system.model.resp.NoticeResp;
|
||||
import top.wms.admin.system.service.NoticeService;
|
||||
import top.continew.starter.core.validation.ValidationUtils;
|
||||
import top.continew.starter.extension.crud.annotation.CrudApi;
|
||||
import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
|
||||
import top.continew.starter.extension.crud.enums.Api;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 公告管理 API
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2023/8/20 10:55
|
||||
*/
|
||||
@Tag(name = "公告管理 API")
|
||||
@RestController
|
||||
@CrudRequestMapping(value = "/system/notice", api = {Api.PAGE, Api.DETAIL, Api.ADD, Api.UPDATE, Api.DELETE})
|
||||
public class NoticeController extends BaseController<NoticeService, NoticeResp, NoticeDetailResp, NoticeQuery, NoticeReq> {
|
||||
|
||||
@Override
|
||||
public void preHandle(CrudApi crudApi, Object[] args, Method targetMethod, Class<?> targetClass) throws Exception {
|
||||
super.preHandle(crudApi, args, targetMethod, targetClass);
|
||||
Api api = crudApi.value();
|
||||
if (!(Api.ADD.equals(api) || Api.UPDATE.equals(api))) {
|
||||
return;
|
||||
}
|
||||
NoticeReq req = (NoticeReq)args[0];
|
||||
// 校验生效时间
|
||||
LocalDateTime effectiveTime = req.getEffectiveTime();
|
||||
LocalDateTime terminateTime = req.getTerminateTime();
|
||||
if (null != effectiveTime && null != terminateTime) {
|
||||
ValidationUtils.throwIf(terminateTime.isBefore(effectiveTime), "终止时间必须晚于生效时间");
|
||||
}
|
||||
// 校验通知范围
|
||||
if (NoticeScopeEnum.USER.equals(req.getNoticeScope())) {
|
||||
ValidationUtils.throwIfEmpty(req.getNoticeUsers(), "通知用户不能为空");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@@ -91,7 +92,8 @@ public class UserController extends BaseController<UserService, UserResp, UserDe
|
||||
ValidationUtils.throwIfNull(rawNewPassword, "新密码解密失败");
|
||||
ValidationUtils.throwIf(!ReUtil
|
||||
.isMatch(RegexConstants.PASSWORD, rawNewPassword), "密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字");
|
||||
req.setNewPassword(rawNewPassword);
|
||||
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
|
||||
req.setNewPassword("{bcrypt}" + encoder.encode(rawNewPassword));
|
||||
baseService.resetPassword(req, id);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package top.wms.admin.controller.tcp.config;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.PreDestroy;
|
||||
import top.wms.admin.controller.tcp.handler.TcpServerHandler;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.*;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.LineBasedFrameDecoder;
|
||||
import io.netty.handler.codec.string.StringDecoder;
|
||||
import io.netty.handler.codec.string.StringEncoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class NettyTcpServer {
|
||||
|
||||
@Value("${tcp.server.port:9005}")
|
||||
private int port;
|
||||
|
||||
@Value("${tcp.server.boss-threads:1}")
|
||||
private int bossThreads;
|
||||
|
||||
@Value("${tcp.server.worker-threads:4}")
|
||||
private int workerThreads;
|
||||
|
||||
private EventLoopGroup bossGroup;
|
||||
private EventLoopGroup workerGroup;
|
||||
private Channel serverChannel;
|
||||
|
||||
@PostConstruct
|
||||
public void start() throws InterruptedException {
|
||||
log.info("正在启动TCP服务端,端口: {}", port);
|
||||
|
||||
bossGroup = new NioEventLoopGroup(bossThreads);
|
||||
workerGroup = new NioEventLoopGroup(workerThreads);
|
||||
|
||||
ServerBootstrap bootstrap = new ServerBootstrap();
|
||||
bootstrap.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.option(ChannelOption.SO_BACKLOG, 128)
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel ch) {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
|
||||
// 解决TCP粘包问题
|
||||
pipeline.addLast(new LineBasedFrameDecoder(1024));
|
||||
|
||||
// 字符串编解码
|
||||
pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
|
||||
pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
|
||||
|
||||
// 关键修复:直接new,不要从Spring容器获取
|
||||
pipeline.addLast(new TcpServerHandler());
|
||||
|
||||
log.debug("新连接接入,处理器已添加");
|
||||
}
|
||||
});
|
||||
|
||||
ChannelFuture future = bootstrap.bind(port).sync();
|
||||
if (future.isSuccess()) {
|
||||
serverChannel = future.channel();
|
||||
log.info("TCP服务端启动成功,端口: {}", port);
|
||||
} else {
|
||||
log.error("TCP服务端启动失败", future.cause());
|
||||
}
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void stop() {
|
||||
log.info("正在关闭TCP服务端...");
|
||||
try {
|
||||
if (serverChannel != null) {
|
||||
serverChannel.close().sync();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
log.error("关闭服务端通道时发生错误", e);
|
||||
} finally {
|
||||
if (bossGroup != null) {
|
||||
bossGroup.shutdownGracefully();
|
||||
}
|
||||
if (workerGroup != null) {
|
||||
workerGroup.shutdownGracefully();
|
||||
}
|
||||
}
|
||||
log.info("TCP服务端已关闭");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package top.wms.admin.controller.tcp.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SimpleRequestMatcher {
|
||||
|
||||
// 用队列存储响应
|
||||
private final BlockingQueue<String> responseQueue = new LinkedBlockingQueue<>(1);
|
||||
|
||||
// 当前等待的请求标识
|
||||
private volatile boolean isWaiting = false;
|
||||
|
||||
/**
|
||||
* 等待响应
|
||||
*/
|
||||
public String waitForResponse(int timeoutSeconds) {
|
||||
isWaiting = true;
|
||||
try {
|
||||
log.info("等待响应, 超时={}秒", timeoutSeconds);
|
||||
// 从队列取响应,最多等待timeoutSeconds秒
|
||||
String response = responseQueue.poll(timeoutSeconds, TimeUnit.SECONDS);
|
||||
if (response != null) {
|
||||
log.info("收到响应: {}", response);
|
||||
return response;
|
||||
} else {
|
||||
log.error("等待响应超时");
|
||||
return "TIMEOUT";
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
log.error("等待响应被中断: {}", e.getMessage());
|
||||
return "ERROR";
|
||||
} finally {
|
||||
isWaiting = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收响应
|
||||
*/
|
||||
public void handleResponse(String response) {
|
||||
try {
|
||||
// 如果有请求在等待,把响应放入队列
|
||||
if (isWaiting) {
|
||||
responseQueue.offer(response);
|
||||
log.info("响应接收成功: {}", response);
|
||||
} else {
|
||||
log.warn("没有正在等待的请求, 响应被丢弃: {}", response);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理响应失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空队列
|
||||
*/
|
||||
public void clear() {
|
||||
responseQueue.clear();
|
||||
isWaiting = false;
|
||||
log.info("请求匹配器已清空");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package top.wms.admin.controller.tcp.handler;
|
||||
|
||||
import top.wms.admin.controller.tcp.config.SimpleRequestMatcher;
|
||||
import top.wms.admin.controller.tcp.util.SpringContextUtil;
|
||||
import top.wms.admin.controller.tcp.manager.ChannelManager;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
public class TcpServerHandler extends SimpleChannelInboundHandler<String> {
|
||||
|
||||
private ChannelManager channelManager;
|
||||
private SimpleRequestMatcher requestMatcher;
|
||||
|
||||
private ChannelManager getChannelManager() {
|
||||
if (channelManager == null) {
|
||||
channelManager = SpringContextUtil.getBean(ChannelManager.class);
|
||||
}
|
||||
return channelManager;
|
||||
}
|
||||
|
||||
private SimpleRequestMatcher getRequestMatcher() {
|
||||
if (requestMatcher == null) {
|
||||
requestMatcher = SpringContextUtil.getBean(SimpleRequestMatcher.class);
|
||||
}
|
||||
return requestMatcher;
|
||||
}
|
||||
|
||||
private String getClientId(ChannelHandlerContext ctx) {
|
||||
return ctx.channel().remoteAddress().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelActive(ChannelHandlerContext ctx) {
|
||||
String clientId = getClientId(ctx);
|
||||
getChannelManager().addChannel(clientId, ctx.channel());
|
||||
log.info("✅ VM客户端连接成功: {}", clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) {
|
||||
String clientId = getClientId(ctx);
|
||||
getChannelManager().removeChannel(clientId);
|
||||
log.info("❌ VM客户端断开连接: {}", clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, String msg) {
|
||||
String clientId = getClientId(ctx);
|
||||
log.info("📥 收到VM数据 [{}]: {}", clientId, msg);
|
||||
|
||||
try {
|
||||
// 直接把收到的消息交给匹配器(不解析,不匹配)
|
||||
String cleanMsg = msg.trim();
|
||||
getRequestMatcher().handleResponse(cleanMsg);
|
||||
} catch (Exception e) {
|
||||
log.error("处理消息失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
log.error("连接异常: {}", cause.getMessage());
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package top.wms.admin.controller.tcp.manager;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ChannelManager {
|
||||
|
||||
// 存储所有VM客户端的连接
|
||||
private final ConcurrentHashMap<String, Channel> channels = new ConcurrentHashMap<>();
|
||||
|
||||
// 添加连接
|
||||
public void addChannel(String clientId, Channel channel) {
|
||||
channels.put(clientId, channel);
|
||||
log.info("VM客户端 [{}] 已连接,当前在线客户端数: {}", clientId, channels.size());
|
||||
}
|
||||
|
||||
// 移除连接
|
||||
public void removeChannel(String clientId) {
|
||||
channels.remove(clientId);
|
||||
log.info("VM客户端 [{}] 已断开,当前在线客户端数: {}", clientId, channels.size());
|
||||
}
|
||||
|
||||
// 获取第一个连接的VM(如果有多个VM,可以根据需要修改)
|
||||
public Channel getFirstChannel() {
|
||||
return channels.values().stream().findFirst().orElse(null);
|
||||
}
|
||||
|
||||
// 根据ID获取连接
|
||||
public Channel getChannel(String clientId) {
|
||||
return channels.get(clientId);
|
||||
}
|
||||
|
||||
// 检查是否有VM连接
|
||||
public boolean hasConnection() {
|
||||
return !channels.isEmpty();
|
||||
}
|
||||
|
||||
// 获取所有连接
|
||||
public ConcurrentHashMap<String, Channel> getAllChannels() {
|
||||
return channels;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package top.wms.admin.controller.tcp.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
// 指令请求
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommandRequest {
|
||||
private String processId; // 要执行的流程ID,如 "PROCESS_1"
|
||||
private String param; // 参数,如 "10.5"
|
||||
private Integer priority; // 优先级(可选)
|
||||
|
||||
// 构建完整的指令字符串
|
||||
public String buildCommand() {
|
||||
// 格式:*PROCESS_1,10.5#
|
||||
return String.format("*%s,%s#", processId, param);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user