配置智能柜锁
This commit is contained in:
parent
7cf2f4dd0c
commit
48e1b88c22
|
@ -0,0 +1,76 @@
|
|||
package com.agileboot.admin.controller.cabinet;
|
||||
|
||||
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.enums.common.BusinessTypeEnum;
|
||||
import com.agileboot.domain.cabinet.cell.CabinetCellApplicationService;
|
||||
import com.agileboot.domain.cabinet.cell.command.AddCabinetCellCommand;
|
||||
import com.agileboot.domain.cabinet.cell.command.UpdateCabinetCellCommand;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellEntity;
|
||||
import com.agileboot.domain.cabinet.cell.dto.CabinetCellDTO;
|
||||
import com.agileboot.domain.cabinet.cell.query.SearchCabinetCellQuery;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/cabinet/cell")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class CabinetCellController extends BaseController {
|
||||
|
||||
private final CabinetCellApplicationService cabinetCellApplicationService;
|
||||
|
||||
@Operation(summary = "格口列表")
|
||||
@GetMapping
|
||||
public ResponseDTO<PageDTO<CabinetCellDTO>> list(SearchCabinetCellQuery<CabinetCellEntity> query) {
|
||||
PageDTO<CabinetCellDTO> page = cabinetCellApplicationService.getCabinetCellList(query);
|
||||
return ResponseDTO.ok(page);
|
||||
}
|
||||
|
||||
@Operation(summary = "新增格口")
|
||||
@AccessLog(title = "格口管理", businessType = BusinessTypeEnum.ADD)
|
||||
@PostMapping
|
||||
public ResponseDTO<Void> add(@Validated @RequestBody AddCabinetCellCommand command) {
|
||||
cabinetCellApplicationService.addCabinetCell(command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "修改格口")
|
||||
@AccessLog(title = "格口管理", businessType = BusinessTypeEnum.MODIFY)
|
||||
@PutMapping("/{cellId}")
|
||||
public ResponseDTO<Void> edit(@PathVariable Long cellId, @Validated @RequestBody UpdateCabinetCellCommand command) {
|
||||
command.setCellId(cellId);
|
||||
cabinetCellApplicationService.updateCabinetCell(command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "删除格口")
|
||||
@AccessLog(title = "格口管理", businessType = BusinessTypeEnum.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public ResponseDTO<Void> remove(@PathVariable @NotNull List<Long> ids) {
|
||||
cabinetCellApplicationService.deleteCabinetCell(new BulkOperationCommand<>(ids));
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "配置格口商品")
|
||||
@AccessLog(title = "格口管理", businessType = BusinessTypeEnum.MODIFY)
|
||||
@PutMapping("/configureGoodsCells/{cellId}/{goodsId}")
|
||||
public ResponseDTO<Void> configureGoodsCells(@PathVariable Long cellId, @PathVariable Long goodsId) {
|
||||
cabinetCellApplicationService.configureGoodsCells(cellId, goodsId);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package com.agileboot.admin.controller.cabinet;
|
||||
|
||||
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.enums.common.BusinessTypeEnum;
|
||||
import com.agileboot.domain.cabinet.cell.CabinetCellApplicationService;
|
||||
import com.agileboot.domain.cabinet.cell.dto.CabinetCellDTO;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.dto.AllCabinetDataDTO;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.SmartCabinetApplicationService;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.command.AddSmartCabinetCommand;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.command.UpdateSmartCabinetCommand;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetEntity;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.dto.SmartCabinetDTO;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.query.SearchSmartCabinetQuery;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/cabinet/smartCabinet")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class SmartCabinetController extends BaseController {
|
||||
|
||||
private final SmartCabinetApplicationService smartCabinetApplicationService;
|
||||
private final CabinetCellApplicationService cabinetCellApplicationService;
|
||||
|
||||
@Operation(summary = "智能柜列表")
|
||||
@GetMapping
|
||||
public ResponseDTO<PageDTO<SmartCabinetDTO>> list(SearchSmartCabinetQuery<SmartCabinetEntity> query) {
|
||||
PageDTO<SmartCabinetDTO> page = smartCabinetApplicationService.getSmartCabinetList(query);
|
||||
return ResponseDTO.ok(page);
|
||||
}
|
||||
|
||||
@Operation(summary = "新增智能柜")
|
||||
@AccessLog(title = "智能柜管理", businessType = BusinessTypeEnum.ADD)
|
||||
@PostMapping
|
||||
public ResponseDTO<Void> add(@Validated @RequestBody AddSmartCabinetCommand command) {
|
||||
smartCabinetApplicationService.addSmartCabinet(command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "修改智能柜")
|
||||
@AccessLog(title = "智能柜管理", businessType = BusinessTypeEnum.MODIFY)
|
||||
@PutMapping("/{id}")
|
||||
public ResponseDTO<Void> edit(@PathVariable Long id, @Validated @RequestBody UpdateSmartCabinetCommand command) {
|
||||
command.setCabinetId(id);
|
||||
smartCabinetApplicationService.updateSmartCabinet(command);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "删除智能柜")
|
||||
@AccessLog(title = "智能柜管理", businessType = BusinessTypeEnum.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public ResponseDTO<Void> remove(@PathVariable @NotNull List<Long> ids) {
|
||||
smartCabinetApplicationService.deleteSmartCabinet(new BulkOperationCommand<>(ids));
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
|
||||
@Operation(summary = "获取所有柜机和格口数据")
|
||||
@GetMapping("/all")
|
||||
public ResponseDTO<AllCabinetDataDTO> getAllCabinetsWithCells() {
|
||||
List<CabinetCellDTO> cells = cabinetCellApplicationService.selectAll().stream()
|
||||
.filter(cell -> cell.getAvailableStatus().equals(1) && cell.getUsageStatus().equals(1))
|
||||
.map(CabinetCellDTO::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<SmartCabinetDTO> cabinets = smartCabinetApplicationService.selectAll().stream()
|
||||
.filter(cabinet -> cells.stream().anyMatch(cell -> cell.getCabinetId().equals(cabinet.getCabinetId())))
|
||||
.map(SmartCabinetDTO::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return ResponseDTO.ok(new AllCabinetDataDTO(cabinets, cells));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.agileboot.admin.controller.common;
|
||||
|
||||
import com.agileboot.infrastructure.cache.RedisUtil;
|
||||
import java.util.Date;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/test")
|
||||
public class TestController {
|
||||
@Value("${spring.redis.host}")
|
||||
private String redisHost;
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private String redisPort;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@GetMapping("/time")
|
||||
public String getTime() {
|
||||
return "version 0.0.1 time:" + String.valueOf(new Date().getTime());
|
||||
}
|
||||
|
||||
@GetMapping("/redisIp")
|
||||
public String getRedisIp() {
|
||||
return "Redis服务ip:" + redisHost + " 端口:" + redisPort;
|
||||
}
|
||||
|
||||
@GetMapping("/testRedis")
|
||||
public String testRedisConnection() {
|
||||
try {
|
||||
String testKey = "shop-back-end:test";
|
||||
long timestamp = new Date().getTime();
|
||||
|
||||
// 写入测试值
|
||||
redisUtil.setCacheObject(testKey, timestamp);
|
||||
// 读取测试值
|
||||
Long storedValue = redisUtil.getCacheObject(testKey);
|
||||
|
||||
if (storedValue != null && storedValue == timestamp) {
|
||||
return "Redis连接正常,读写测试通过";
|
||||
}
|
||||
return "Redis读写测试异常:读取值与写入值不匹配";
|
||||
} catch (RedisConnectionFailureException e) {
|
||||
return "Redis连接失败:" + e.getMessage();
|
||||
} catch (Exception e) {
|
||||
return "Redis操作异常:" + e.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.agileboot.admin.controller.qywx;
|
||||
|
||||
import com.agileboot.admin.customize.aop.accessLog.AccessLog;
|
||||
import com.agileboot.admin.customize.service.QywxScheduleJob;
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
|
@ -12,10 +13,15 @@ import com.agileboot.domain.qywx.department.command.UpdateDepartmentCommand;
|
|||
import com.agileboot.domain.qywx.department.db.QyDepartmentEntity;
|
||||
import com.agileboot.domain.qywx.department.dto.QyDepartmentDTO;
|
||||
import com.agileboot.domain.qywx.department.query.SearchQyDepartmentQuery;
|
||||
import com.agileboot.domain.qywx.template.command.UpdateTemplateCommand;
|
||||
import com.agileboot.domain.qywx.template.db.QyTemplateEntity;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
@ -24,15 +30,18 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/qywx/departments")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class QyDepartmentController extends BaseController {
|
||||
|
||||
private final DepartmentApplicationService departmentApplicationService;
|
||||
private final QywxScheduleJob qywxScheduleJob;
|
||||
|
||||
@Operation(summary = "部门列表")
|
||||
@GetMapping
|
||||
|
@ -65,4 +74,16 @@ public class QyDepartmentController extends BaseController {
|
|||
departmentApplicationService.deleteDepartment(new BulkOperationCommand<>(ids));
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/syncDepartmentInfo")
|
||||
public String syncDepartmentInfo(@RequestParam String appid) {
|
||||
try {
|
||||
qywxScheduleJob.syncDepartmentInfo(appid);
|
||||
return "success";
|
||||
} catch (Exception e) {
|
||||
log.error("syncDepartmentInfo error", e);
|
||||
return e.getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -137,7 +137,7 @@ public class SecurityConfig {
|
|||
.antMatchers("/login", "/register", "/getConfig", "/captchaImage", "/api/**", "/file/**").anonymous()
|
||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js",
|
||||
"/profile/**").permitAll()
|
||||
.antMatchers("/qywx/**").permitAll()
|
||||
.antMatchers("/qywx/**", "/test/**").permitAll()
|
||||
// TODO this is danger.
|
||||
.antMatchers("/swagger-ui.html").anonymous()
|
||||
.antMatchers("/swagger-resources/**").anonymous()
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.agileboot.admin.customize.service;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.qywx.accessToken.AccessTokenApplicationService;
|
||||
import com.agileboot.domain.qywx.accessToken.db.QyAccessTokenEntity;
|
||||
import com.agileboot.domain.qywx.api.QywxApiUtil;
|
||||
|
@ -10,6 +12,8 @@ import com.agileboot.domain.qywx.api.response.DepartmentListResponse;
|
|||
import com.agileboot.domain.qywx.authCorpInfo.AuthCorpInfoApplicationService;
|
||||
import com.agileboot.domain.qywx.authCorpInfo.db.QyAuthCorpInfoEntity;
|
||||
import com.agileboot.domain.qywx.department.DepartmentApplicationService;
|
||||
import com.agileboot.domain.qywx.department.command.AddDepartmentCommand;
|
||||
import com.agileboot.domain.qywx.department.command.UpdateDepartmentCommand;
|
||||
import com.agileboot.domain.qywx.department.db.QyDepartmentEntity;
|
||||
import com.agileboot.domain.qywx.template.TemplateApplicationService;
|
||||
import com.agileboot.domain.qywx.template.command.UpdateTemplateCommand;
|
||||
|
@ -23,6 +27,7 @@ import java.util.stream.Collectors;
|
|||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
@ -59,6 +64,9 @@ public class QywxScheduleJob {
|
|||
|
||||
try {
|
||||
QyTemplateEntity template = templateApplicationService.getByAppid(appid);
|
||||
if (null == template) {
|
||||
return;
|
||||
}
|
||||
String suiteAccessToken = templateApplicationService.getSuiteAccessToken(template.getSuiteId(), template.getSecret(),
|
||||
template.getSuiteTicket());
|
||||
|
||||
|
@ -95,13 +103,13 @@ public class QywxScheduleJob {
|
|||
return;
|
||||
}
|
||||
|
||||
accessTokenApplicationService.getAccessToken(authCorpInfo.getSuiteId(), authCorpInfo.getPermanentCode(), appid);
|
||||
accessTokenApplicationService.getAccessToken(authCorpInfo.getCorpid(), authCorpInfo.getPermanentCode(), appid);
|
||||
} catch (Exception e) {
|
||||
log.error("getAccessToken error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 0 * * * *")
|
||||
@Scheduled(cron = "0 30 * * * *")
|
||||
public void syncDepartmentInfoTask() {
|
||||
try {
|
||||
syncDepartmentInfo(appid);
|
||||
|
@ -188,39 +196,63 @@ public class QywxScheduleJob {
|
|||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
// 执行数据库操作
|
||||
if (!toAdd.isEmpty()) {
|
||||
List<QyDepartmentEntity> newDeptList = toAdd.stream()
|
||||
List<AddDepartmentCommand> newDeptList = toAdd.stream()
|
||||
.map(d -> {
|
||||
QyDepartmentEntity entity = new QyDepartmentEntity();
|
||||
entity.setDepartmentId(String.valueOf(d.getId()));
|
||||
entity.setName(d.getName());
|
||||
entity.setNameEn(d.getName_en());
|
||||
AddDepartmentCommand command = new AddDepartmentCommand();
|
||||
command.setDepartmentId(String.valueOf(d.getId()));
|
||||
command.setName(d.getName());
|
||||
command.setNameEn(d.getName_en());
|
||||
String leader = String.join(",", d.getDepartment_leader());
|
||||
if (leader.length() > 255) {
|
||||
leader = leader.substring(0, 255);
|
||||
}
|
||||
entity.setDepartmentLeader(leader);
|
||||
entity.setParentid(String.valueOf(d.getParentid()));
|
||||
entity.setAppid(appid);
|
||||
entity.setEnable("1");
|
||||
return entity;
|
||||
command.setDepartmentLeader(leader);
|
||||
command.setParentid(String.valueOf(d.getParentid()));
|
||||
command.setAppid(appid);
|
||||
command.setEnable("1");
|
||||
command.setCreatorId(0L);
|
||||
command.setCreateTime(new Date());
|
||||
command.setUpdaterId(0L);
|
||||
command.setUpdateTime(new Date());
|
||||
command.setDeleted(false);
|
||||
return command;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
departmentApplicationService.batchInsertDepartments(newDeptList);
|
||||
|
||||
for (AddDepartmentCommand command : newDeptList) {
|
||||
log.info("syncDepartmentInfo new: {}", JSONUtil.toJsonStr(command));
|
||||
departmentApplicationService.addDepartment(command);
|
||||
}
|
||||
}
|
||||
if (!toUpdate.isEmpty()) {
|
||||
departmentApplicationService.batchUpdateDepartments(toUpdate);
|
||||
List<UpdateDepartmentCommand> updateDeptList = toUpdate.stream()
|
||||
.map(d -> {
|
||||
UpdateDepartmentCommand command = new UpdateDepartmentCommand();
|
||||
BeanUtils.copyProperties(d, command);
|
||||
return command;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("syncDepartmentInfo updateDeptList: {}", updateDeptList);
|
||||
for (UpdateDepartmentCommand command : updateDeptList) {
|
||||
departmentApplicationService.updateDepartment(command);
|
||||
}
|
||||
}
|
||||
if (!toRemove.isEmpty()) {
|
||||
departmentApplicationService.batchDeleteDepartments(
|
||||
BulkOperationCommand<Integer> command = new BulkOperationCommand<>(
|
||||
toRemove.stream().map(QyDepartmentEntity::getId).collect(Collectors.toList())
|
||||
);
|
||||
log.info("syncDepartmentInfo command: {}", command);
|
||||
departmentApplicationService.deleteDepartment(command);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("syncDepartmentInfo error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
package com.agileboot.api.controller;
|
||||
|
||||
import com.agileboot.infrastructure.cache.RedisUtil;
|
||||
import java.util.Date;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.RedisConnectionFailureException;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -12,8 +17,44 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
@RequestMapping("/api/monitor")
|
||||
public class MonitorController {
|
||||
|
||||
@Value("${spring.redis.host}")
|
||||
private String redisHost;
|
||||
|
||||
@Value("${spring.redis.port}")
|
||||
private String redisPort;
|
||||
|
||||
@Autowired
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@GetMapping("/time")
|
||||
public String getTime() {
|
||||
return "version 0.0.1 time:" + String.valueOf(new Date().getTime());
|
||||
}
|
||||
|
||||
@GetMapping("/redisIp")
|
||||
public String getRedisIp() {
|
||||
return "Redis服务ip:" + redisHost + " 端口:" + redisPort;
|
||||
}
|
||||
|
||||
@GetMapping("/testRedis")
|
||||
public String testRedisConnection() {
|
||||
try {
|
||||
String testKey = "shop-back-end:test";
|
||||
long timestamp = new Date().getTime();
|
||||
|
||||
// 写入测试值
|
||||
redisUtil.setCacheObject(testKey, timestamp);
|
||||
// 读取测试值
|
||||
Long storedValue = redisUtil.getCacheObject(testKey);
|
||||
|
||||
if (storedValue != null && storedValue == timestamp) {
|
||||
return "Redis连接正常,读写测试通过";
|
||||
}
|
||||
return "Redis读写测试异常:读取值与写入值不匹配";
|
||||
} catch (RedisConnectionFailureException e) {
|
||||
return "Redis连接失败:" + e.getMessage();
|
||||
} catch (Exception e) {
|
||||
return "Redis操作异常:" + e.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.agileboot.api.controller;
|
||||
|
||||
import com.agileboot.domain.mqtt.BCCCalculator;
|
||||
import com.agileboot.domain.mqtt.MqttService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/mqtt")
|
||||
@CrossOrigin(origins = "*", allowedHeaders = "*")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class MqttController {
|
||||
private final MqttService mqttService;
|
||||
|
||||
|
||||
@GetMapping("/opencell")
|
||||
public String opencell(@RequestParam String data) {
|
||||
try {
|
||||
mqttService.publish(data);
|
||||
return "success";
|
||||
} catch (Exception e) {
|
||||
log.error("getPermanentCode error", e);
|
||||
return e.getLocalizedMessage();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,10 @@ package com.agileboot.api.controller;
|
|||
|
||||
import com.agileboot.common.core.base.BaseController;
|
||||
import com.agileboot.domain.shop.order.dto.CreateOrderResult;
|
||||
import com.agileboot.domain.shop.order.dto.GetOrdersByOpenIdDTO;
|
||||
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 com.agileboot.common.core.dto.ResponseDTO;
|
||||
|
@ -30,4 +33,16 @@ public class OrderController extends BaseController {
|
|||
CreateOrderResult result = orderApplicationService.createOrder(command);
|
||||
return ResponseDTO.ok(result);
|
||||
}
|
||||
|
||||
@PostMapping("/openCabinet/{orderId}/{orderGoodsId}")
|
||||
public ResponseDTO<?> openCabinet(@PathVariable Long orderId, @PathVariable Long orderGoodsId) {
|
||||
orderApplicationService.openOrderGoodsCabinet(orderId, orderGoodsId);
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/user/{openid}")
|
||||
public ResponseDTO<GetOrdersByOpenIdDTO> getOrdersByOpenId(@PathVariable String openid) {
|
||||
GetOrdersByOpenIdDTO result = orderApplicationService.getOrdersByOpenId(openid);
|
||||
return ResponseDTO.ok(result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.agileboot.common.exception.ApiException;
|
|||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.common.exception.error.ErrorCode.Client;
|
||||
import com.agileboot.common.utils.OpenSignUtil;
|
||||
import com.agileboot.domain.shop.order.OrderApplicationService;
|
||||
import com.agileboot.domain.shop.payment.dto.PaymentCallbackRequest;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
|
@ -16,6 +17,7 @@ import java.util.Map;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
|
@ -34,9 +36,12 @@ import org.springframework.web.client.RestTemplate;
|
|||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/payment")
|
||||
public class PaymentController {
|
||||
private final OrderApplicationService orderApplicationService;
|
||||
|
||||
// 新增回调接口
|
||||
@PostMapping("/callback")
|
||||
public String paymentCallback(HttpServletRequest request, @RequestBody String requestBody) {
|
||||
log.info("支付回调requestBody:{}", requestBody);
|
||||
try {
|
||||
// 1. 参数解析
|
||||
PaymentCallbackRequest callbackReq = parseCallbackRequest(requestBody);
|
||||
|
@ -47,16 +52,21 @@ public class PaymentController {
|
|||
boolean signValid = OpenSignUtil.checkOpenSign(appKey, callbackReq.getSign(), requestBody);
|
||||
|
||||
if (!signValid) {
|
||||
log.error("签名验证失败:{}", requestBody);
|
||||
log.error("支付回调签名验证失败:{}", requestBody);
|
||||
return "fail";
|
||||
}
|
||||
|
||||
// 3. 业务处理(需要实现幂等性校验)
|
||||
handlePaymentSuccess(
|
||||
bizContent.getBiz_order_id(),
|
||||
bizContent.getTotal_amount(),
|
||||
bizContent.getTrade_id()
|
||||
);
|
||||
if (bizContent.getTrade_status().equals("SUCCESS")) {
|
||||
// 3. 业务处理(需要实现幂等性校验)
|
||||
handlePaymentSuccess(
|
||||
bizContent.getBiz_order_id(),
|
||||
bizContent.getTotal_amount(),
|
||||
bizContent.getTrade_id(),
|
||||
bizContent.getTrade_pay_time()
|
||||
);
|
||||
} else {
|
||||
log.error("支付订单失败requestBody:{}", requestBody);
|
||||
}
|
||||
|
||||
return "success";
|
||||
} catch (Exception e) {
|
||||
|
@ -113,7 +123,12 @@ public class PaymentController {
|
|||
return "wxshop202503081132";
|
||||
}
|
||||
|
||||
private void handlePaymentSuccess(String bizOrderId, Integer amount, String tradeId) {
|
||||
private void handlePaymentSuccess(String bizOrderId, Integer amount, String tradeId, String tradePayTime) {
|
||||
// 实现订单状态更新和幂等性校验
|
||||
if (StringUtils.isNotBlank(bizOrderId) && bizOrderId.startsWith("wxshop-")) {
|
||||
// 订单号格式为 wxshop-1-time,提取中间的订单号
|
||||
String orderId = bizOrderId.split("-")[1];
|
||||
orderApplicationService.handlePaymentSuccess(Long.valueOf(orderId), amount, tradeId, tradePayTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.agileboot.api.controller;
|
||||
|
||||
import com.agileboot.api.response.ShopGoodsResponse;
|
||||
import com.agileboot.common.constant.WeixinConstants;
|
||||
import com.agileboot.common.core.dto.ResponseDTO;
|
||||
import com.agileboot.domain.shop.category.CategoryApplicationService;
|
||||
import com.agileboot.domain.shop.category.dto.ShopCategoryDTO;
|
||||
|
@ -12,6 +13,7 @@ import org.springframework.web.bind.annotation.CrossOrigin;
|
|||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/shop")
|
||||
|
@ -25,10 +27,27 @@ public class ShopController {
|
|||
public ResponseDTO<ShopGoodsResponse> getShopGoodsInfo() {
|
||||
// 获取商品列表
|
||||
List<ShopGoodsEntity> goodsList = goodsApplicationService.getGoodsAll();
|
||||
goodsList.forEach(goods -> {
|
||||
// 最多只能购买一件
|
||||
if (!goods.getStock().equals(0)) {
|
||||
goods.setStock(1);
|
||||
}
|
||||
});
|
||||
// 获取分类列表
|
||||
List<ShopCategoryDTO> categoryList = categoryApplicationService.getCategoryAll();
|
||||
|
||||
|
||||
return ResponseDTO.ok(new ShopGoodsResponse(goodsList, categoryList, "0"));
|
||||
}
|
||||
|
||||
@GetMapping("/wechatAuth")
|
||||
public RedirectView wechatAuthRedirect() {
|
||||
String authUrl = "https://open.weixin.qq.com/connect/oauth2/authorize"
|
||||
+ "?appid=" + WeixinConstants.appid
|
||||
+ "&redirect_uri=http%3A%2F%2Fwxshop.ab98.cn%2Fshop"
|
||||
+ "&response_type=code"
|
||||
+ "&scope=snsapi_base"
|
||||
+ "&state=STATE#wechat_redirect";
|
||||
return new RedirectView(authUrl);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package com.agileboot.common.constant;
|
||||
|
||||
public class WeixinConstants {
|
||||
public static String appid = "wx04e357a5a0900f24";
|
||||
public static String secret = "2a5a8b6ad3654a05f9fdd36524279a50";
|
||||
// public static String appid = "wx04e357a5a0900f24";
|
||||
// public static String secret = "2a5a8b6ad3654a05f9fdd36524279a50";
|
||||
public static String appid = "wx9922dfbb0d4cd7bb";
|
||||
public static String secret = "7c7ef0dbb90b6be2abc8c269357f980a";
|
||||
}
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
package com.agileboot.common.utils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.TreeMap;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.codec.digest.Md5Crypt;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.hutool.crypto.SecureUtil.md5;
|
||||
|
||||
|
@ -38,10 +41,20 @@ public class OpenSignUtil {
|
|||
return Objects.equals(generateSign, sign);
|
||||
}
|
||||
|
||||
private static List<String> getKVList(Map<String, String> sortedParams) {
|
||||
return sortedParams.entrySet().stream()
|
||||
.map(entry -> entry.getKey() + "=" + entry.getValue())
|
||||
.collect(Collectors.toList());
|
||||
public static List<String> getKVList(Map<String, String> params) {
|
||||
if(MapUtils.isEmpty(params)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<String> kvPairs = new ArrayList<>();
|
||||
for(String key : params.keySet()) {
|
||||
String value = params.get(key);
|
||||
if(value == null) {
|
||||
continue;
|
||||
}
|
||||
String kv = key + "=" + value;
|
||||
kvPairs.add(kv);
|
||||
}
|
||||
return kvPairs;
|
||||
}
|
||||
|
||||
public static String openSign(String appKey, Map<String, String> params) {
|
||||
|
@ -54,10 +67,22 @@ public class OpenSignUtil {
|
|||
sourceText = sourceText + "&app_key=" + appKey;
|
||||
log.info("sourceText:{}", sourceText);
|
||||
try {
|
||||
return md5(Arrays.toString(sourceText.getBytes(StandardCharsets.UTF_8)));
|
||||
// MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
// String res = new String(md.digest(sourceText.getBytes("utf-8")));
|
||||
String res = md5(sourceText);
|
||||
log.info("md5:{}", res);
|
||||
return res;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String body = "biz_content=%7B%22uid%22%3A%22174246"
|
||||
+ "2448492%22%2C%22trade_id%22%3A%221063669415%22%2C%22total_amount%22%3A1%2C%22extra%22%3A%22%22%2C%22trade_pay_time%22%3A%222025-03-20+17%3A20%3A55%22%2C%22trade_status%22%3A%22SUCCESS%22%2C%22pay_type%22%3A%22116%22%2C%22callback_content%22%3A%22%3Cxml%3E%3Cappid%3E%3C%21%5BCDATA%5Bwx9922dfbb0d4cd7bb%5D%5D%3E%3C%2Fappid%3E%5Cn%3Cattach%3E%3C%21%5BCDATA%5B%257B%2522biz_id%2522%253A%2522wxshop%2522%252C%2522trade_id%2522%253A%25221063669415%2522%257D%5D%5D%3E%3C%2Fattach%3E%5Cn%3Cbank_type%3E%3C%21%5BCDATA%5BOTHERS%5D%5D%3E%3C%2Fbank_type%3E%5Cn%3Ccash_fee%3E%3C%21%5BCDATA%5B1%5D%5D%3E%3C%2Fcash_fee%3E%5Cn%3Cfee_type%3E%3C%21%5BCDATA%5BCNY%5D%5D%3E%3C%2Ffee_type%3E%5Cn%3Cis_subscribe%3E%3C%21%5BCDATA%5BN%5D%5D%3E%3C%2Fis_subscribe%3E%5Cn%3Cmch_id%3E%3C%21%5BCDATA%5B1625101806%5D%5D%3E%3C%2Fmch_id%3E%5Cn%3Cnonce_str%3E%3C%21%5BCDATA%5B24NffiTHxNYm0ppw3QE9WezmzJQDnJQV%5D%5D%3E%3C%2Fnonce_str%3E%5Cn%3Copenid%3E%3C%21%5BCDATA%5BoMRxw6Eum0DB1IjI_pEX_yrawBHw%5D%5D%3E%3C%2Fopenid%3E%5Cn%3Cout_trade_no%3E%3C%21%5BCDATA"
|
||||
+ "%5Bwxshop-10-1742462448212%5D%5D%3E%3C%2Fout_trade_no%3E%5Cn%3Cresult_code%3E%3C%21%5BCDATA%5BSUCCESS%5D%5D%3E%3C%2Fresult_code%3E%5Cn%3Creturn_code%3E%3C%21%5BCDATA%5BSUCCESS%5D%5D%3E%3C%2Freturn_code%3E%5Cn%3Csign%3E%3C%21%5BCDATA%5B9CE8A123437E591166DDAF92A750C122%5D%5D%3E%3C%2Fsign%3E%5Cn%3Ctime_end%3E%3C%21%5BCDATA%5B20250320172055%5D%5D%3E%3C%2Ftime_end%3E%5Cn%3Ctotal_fee%3E1%3C%2Ftotal_fee%3E%5Cn%3Ctrade_type%3E%3C%21%5BCDATA%5BJSAPI%5D%5D%3E%3C%2Ftrade_type%3E%5Cn%3Ctransaction_id%3E%3C%21%5BCDATA%5B4200002695202503209706830758%5D%5D%3E%3C%2Ftransaction_id%3E%5Cn%3C%2Fxml%3E%22%2C%22title%22%3A%22%E5%95%86%E5%93%81%E8%AE%A2%E5%8D%95%E6%94%AF%E4%BB%98%22%2C%22biz_order_id%22%3A%22wxshop-10-1742462448212%22%7D&nonce_str=6d80bd6b542a499994adf4ee4c1e89c4&sign=f1ffc9cfc61cf60d8a1acbac0399cd0b&biz_id=wxshop&sign_type=MD5&version=1.0×tamp=1742462460390";
|
||||
|
||||
Boolean res = checkOpenSign("wxshop202503081132", "f1ffc9cfc61cf60d8a1acbac0399cd0b", body);
|
||||
log.info("res:{}", res);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,11 @@
|
|||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.paho</groupId>
|
||||
<artifactId>org.eclipse.paho.client.mqttv3</artifactId>
|
||||
<version>1.2.5</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package com.agileboot.domain.cabinet.cell;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.cabinet.cell.command.AddCabinetCellCommand;
|
||||
import com.agileboot.domain.cabinet.cell.command.UpdateCabinetCellCommand;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellEntity;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellService;
|
||||
import com.agileboot.domain.cabinet.cell.dto.CabinetCellDTO;
|
||||
import com.agileboot.domain.cabinet.cell.model.CabinetCellModel;
|
||||
import com.agileboot.domain.cabinet.cell.model.CabinetCellModelFactory;
|
||||
import com.agileboot.domain.cabinet.cell.query.SearchCabinetCellQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CabinetCellApplicationService {
|
||||
private final CabinetCellService cabinetCellService;
|
||||
private final CabinetCellModelFactory cabinetCellModelFactory;
|
||||
|
||||
public PageDTO<CabinetCellDTO> getCabinetCellList(SearchCabinetCellQuery<CabinetCellEntity> query) {
|
||||
Page<CabinetCellEntity> page = cabinetCellService.getCellList(query);
|
||||
List<CabinetCellDTO> dtoList = page.getRecords().stream()
|
||||
.map(CabinetCellDTO::new)
|
||||
.collect(Collectors.toList());
|
||||
return new PageDTO<>(dtoList, page.getTotal());
|
||||
}
|
||||
|
||||
public void addCabinetCell(AddCabinetCellCommand command) {
|
||||
CabinetCellModel model = cabinetCellModelFactory.create();
|
||||
model.loadAddCommand(command);
|
||||
model.insert();
|
||||
}
|
||||
|
||||
public void updateCabinetCell(UpdateCabinetCellCommand command) {
|
||||
CabinetCellModel model = cabinetCellModelFactory.loadById(command.getCellId());
|
||||
model.loadUpdateCommand(command);
|
||||
model.updateById();
|
||||
}
|
||||
|
||||
public void deleteCabinetCell(BulkOperationCommand<Long> command) {
|
||||
for (Long cellId : command.getIds()) {
|
||||
CabinetCellModel model = cabinetCellModelFactory.loadById(cellId);
|
||||
model.deleteById();
|
||||
}
|
||||
}
|
||||
|
||||
public List<CabinetCellEntity> selectAll() {
|
||||
return cabinetCellService.selectAll();
|
||||
}
|
||||
|
||||
public void configureGoodsCells(Long cellId, Long goodsId) {
|
||||
List<CabinetCellEntity> cells = cabinetCellService.selectByGoodsId(goodsId);
|
||||
for (CabinetCellEntity cell : cells) {
|
||||
cell.setGoodsId(null);
|
||||
cell.setUsageStatus(1);
|
||||
cell.updateById();
|
||||
}
|
||||
|
||||
CabinetCellModel model = cabinetCellModelFactory.loadById(cellId);
|
||||
model.setGoodsId(goodsId);
|
||||
model.setUsageStatus(2);
|
||||
model.updateById();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.agileboot.domain.cabinet.cell.command;
|
||||
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class AddCabinetCellCommand extends CabinetCellEntity {
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.agileboot.domain.cabinet.cell.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class UpdateCabinetCellCommand extends AddCabinetCellCommand {
|
||||
|
||||
@NotNull
|
||||
@PositiveOrZero
|
||||
private Long cellId;
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.agileboot.domain.cabinet.cell.db;
|
||||
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 柜机格口信息表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2025-03-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("cabinet_cell")
|
||||
@ApiModel(value = "CabinetCellEntity对象", description = "柜机格口信息表")
|
||||
public class CabinetCellEntity extends BaseEntity<CabinetCellEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("格口唯一ID")
|
||||
@TableId(value = "cell_id", type = IdType.AUTO)
|
||||
private Long cellId;
|
||||
|
||||
@ApiModelProperty("关联柜机ID")
|
||||
@TableField("cabinet_id")
|
||||
private Long cabinetId;
|
||||
|
||||
@ApiModelProperty("格口号")
|
||||
@TableField("cell_no")
|
||||
private Integer cellNo;
|
||||
|
||||
@ApiModelProperty("针脚序号")
|
||||
@TableField("pin_no")
|
||||
private Integer pinNo;
|
||||
|
||||
@ApiModelProperty("格口类型(1小格 2中格 3大格 4超大格)")
|
||||
@TableField("cell_type")
|
||||
private Integer cellType;
|
||||
|
||||
@ApiModelProperty("使用状态(1空闲 2已占用)")
|
||||
@TableField("usage_status")
|
||||
private Integer usageStatus;
|
||||
|
||||
@ApiModelProperty("可用状态(1正常 2故障)")
|
||||
@TableField("available_status")
|
||||
private Integer availableStatus;
|
||||
|
||||
@ApiModelProperty("关联商品ID")
|
||||
@TableField("goods_id")
|
||||
private Long goodsId;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.cellId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.agileboot.domain.cabinet.cell.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 柜机格口信息表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2025-03-17
|
||||
*/
|
||||
public interface CabinetCellMapper extends BaseMapper<CabinetCellEntity> {
|
||||
|
||||
@Select("SELECT * " +
|
||||
"FROM cabinet_cell " +
|
||||
"${ew.customSqlSegment}")
|
||||
Page<CabinetCellEntity> getCellList(
|
||||
Page<CabinetCellEntity> page,
|
||||
@Param(Constants.WRAPPER) Wrapper<CabinetCellEntity> queryWrapper
|
||||
);
|
||||
|
||||
@Select("SELECT * " +
|
||||
"FROM cabinet_cell " +
|
||||
"WHERE available_status = 1 " +
|
||||
"ORDER BY cell_id DESC " +
|
||||
"LIMIT 1")
|
||||
CabinetCellEntity selectFirstEnabledCell();
|
||||
|
||||
@Select("SELECT * " +
|
||||
"FROM cabinet_cell " +
|
||||
"WHERE available_status = 1 " +
|
||||
"ORDER BY cell_id DESC")
|
||||
List<CabinetCellEntity> selectAll();
|
||||
|
||||
@Select("SELECT * " +
|
||||
"FROM cabinet_cell " +
|
||||
"WHERE goods_id = #{goodsId} " +
|
||||
"ORDER BY cell_id DESC")
|
||||
List<CabinetCellEntity> selectByGoodsId(@Param("goodsId")Long goodsId);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.agileboot.domain.cabinet.cell.db;
|
||||
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 柜机格口信息表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2025-03-17
|
||||
*/
|
||||
public interface CabinetCellService extends IService<CabinetCellEntity> {
|
||||
|
||||
Page<CabinetCellEntity> getCellList(AbstractPageQuery<CabinetCellEntity> query);
|
||||
|
||||
List<CabinetCellEntity> selectAll();
|
||||
|
||||
List<CabinetCellEntity> selectByGoodsId(Long goodsId);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.agileboot.domain.cabinet.cell.db;
|
||||
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 柜机格口信息表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2025-03-17
|
||||
*/
|
||||
@Service
|
||||
public class CabinetCellServiceImpl extends ServiceImpl<CabinetCellMapper, CabinetCellEntity> implements CabinetCellService {
|
||||
|
||||
@Override
|
||||
public Page<CabinetCellEntity> getCellList(AbstractPageQuery<CabinetCellEntity> query) {
|
||||
return baseMapper.getCellList(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CabinetCellEntity> selectAll() {
|
||||
LambdaQueryWrapper<CabinetCellEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CabinetCellEntity> selectByGoodsId(Long goodsId) {
|
||||
return baseMapper.selectByGoodsId(goodsId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package com.agileboot.domain.cabinet.cell.dto;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.common.annotation.ExcelSheet;
|
||||
import com.agileboot.domain.common.cache.CacheCenter;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellEntity;
|
||||
import com.agileboot.domain.system.user.db.SysUserEntity;
|
||||
import lombok.Data;
|
||||
|
||||
@ExcelSheet(name = "柜机格口信息列表")
|
||||
@Data
|
||||
public class CabinetCellDTO {
|
||||
|
||||
public CabinetCellDTO(CabinetCellEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
|
||||
/* SysUserEntity creator = CacheCenter.userCache.getObjectById(entity.getOperId());
|
||||
if (creator != null) {
|
||||
this.operator = creator.getUsername();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@ExcelColumn(name = "格口ID")
|
||||
private Long cellId;
|
||||
|
||||
@ExcelColumn(name = "关联柜机ID")
|
||||
private Long cabinetId;
|
||||
|
||||
@ExcelColumn(name = "格口号")
|
||||
private Integer cellNo;
|
||||
|
||||
@ExcelColumn(name = "针脚序号")
|
||||
private Integer pinNo;
|
||||
|
||||
@ExcelColumn(name = "格口类型")
|
||||
private Integer cellType;
|
||||
|
||||
@ExcelColumn(name = "使用状态")
|
||||
private Integer usageStatus;
|
||||
|
||||
@ExcelColumn(name = "可用状态")
|
||||
private Integer availableStatus;
|
||||
|
||||
@ExcelColumn(name = "关联商品ID")
|
||||
private Long goodsId;
|
||||
|
||||
@ExcelColumn(name = "操作人")
|
||||
private String operator;
|
||||
|
||||
private String convertUsageStatus(Integer status) {
|
||||
switch (status) {
|
||||
case 1: return "空闲";
|
||||
case 2: return "已占用";
|
||||
default: return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
private String convertAvailableStatus(Integer status) {
|
||||
switch (status) {
|
||||
case 1: return "正常";
|
||||
case 2: return "故障";
|
||||
default: return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
private String convertCellType(Integer type) {
|
||||
switch (type) {
|
||||
case 1: return "小格";
|
||||
case 2: return "中格";
|
||||
case 3: return "大格";
|
||||
case 4: return "超大格";
|
||||
default: return "未知类型";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.agileboot.domain.cabinet.cell.model;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.cabinet.cell.command.AddCabinetCellCommand;
|
||||
import com.agileboot.domain.cabinet.cell.command.UpdateCabinetCellCommand;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellEntity;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellService;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class CabinetCellModel extends CabinetCellEntity {
|
||||
|
||||
private CabinetCellService cabinetCellService;
|
||||
|
||||
public CabinetCellModel(CabinetCellEntity entity, CabinetCellService cabinetCellService) {
|
||||
this(cabinetCellService);
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
}
|
||||
}
|
||||
|
||||
public CabinetCellModel(CabinetCellService cabinetCellService) {
|
||||
this.cabinetCellService = cabinetCellService;
|
||||
}
|
||||
|
||||
public void loadAddCommand(AddCabinetCellCommand command) {
|
||||
if (command != null) {
|
||||
BeanUtil.copyProperties(command, this, "cellId");
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUpdateCommand(UpdateCabinetCellCommand command) {
|
||||
if (command != null) {
|
||||
loadAddCommand(command);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.agileboot.domain.cabinet.cell.model;
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellEntity;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CabinetCellModelFactory {
|
||||
|
||||
private final CabinetCellService cabinetCellService;
|
||||
|
||||
public CabinetCellModel loadById(Long cellId) {
|
||||
CabinetCellEntity entity = cabinetCellService.getById(cellId);
|
||||
if (entity == null) {
|
||||
throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, cellId, "柜机格口");
|
||||
}
|
||||
return new CabinetCellModel(entity, cabinetCellService);
|
||||
}
|
||||
|
||||
public CabinetCellModel create() {
|
||||
return new CabinetCellModel(cabinetCellService);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.agileboot.domain.cabinet.cell.query;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class SearchCabinetCellQuery<T> extends AbstractPageQuery<T> {
|
||||
|
||||
private Long cellId;
|
||||
private Long cabinetId;
|
||||
private Integer cellNo;
|
||||
private Integer cellType;
|
||||
private Integer usageStatus;
|
||||
private Integer availableStatus;
|
||||
private Date startTime;
|
||||
private Date endTime;
|
||||
|
||||
@Override
|
||||
public QueryWrapper<T> addQueryCondition() {
|
||||
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
queryWrapper
|
||||
.eq(cellId != null, "cell_id", cellId)
|
||||
.eq(cabinetId != null, "cabinet_id", cabinetId)
|
||||
.eq(cellNo != null, "cell_no", cellNo)
|
||||
.eq(cellType != null, "cell_type", cellType)
|
||||
.eq(usageStatus != null, "usage_status", usageStatus)
|
||||
.eq(availableStatus != null, "available_status", availableStatus)
|
||||
.between(startTime != null && endTime != null, "create_time", startTime, endTime);
|
||||
|
||||
this.timeRangeColumn = "create_time";
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet;
|
||||
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.command.AddSmartCabinetCommand;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.command.UpdateSmartCabinetCommand;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetEntity;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetService;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.dto.SmartCabinetDTO;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.model.SmartCabinetModel;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.model.SmartCabinetModelFactory;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.query.SearchSmartCabinetQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SmartCabinetApplicationService {
|
||||
private final SmartCabinetService smartCabinetService;
|
||||
private final SmartCabinetModelFactory smartCabinetModelFactory;
|
||||
|
||||
public PageDTO<SmartCabinetDTO> getSmartCabinetList(SearchSmartCabinetQuery<SmartCabinetEntity> query) {
|
||||
Page<SmartCabinetEntity> page = smartCabinetService.getCabinetList(query);
|
||||
List<SmartCabinetDTO> dtoList = page.getRecords().stream()
|
||||
.map(SmartCabinetDTO::new)
|
||||
.collect(Collectors.toList());
|
||||
return new PageDTO<>(dtoList, page.getTotal());
|
||||
}
|
||||
|
||||
public void addSmartCabinet(AddSmartCabinetCommand command) {
|
||||
SmartCabinetModel model = smartCabinetModelFactory.create();
|
||||
model.loadAddCommand(command);
|
||||
model.insert();
|
||||
}
|
||||
|
||||
public void updateSmartCabinet(UpdateSmartCabinetCommand command) {
|
||||
SmartCabinetModel model = smartCabinetModelFactory.loadById(command.getCabinetId());
|
||||
model.loadUpdateCommand(command);
|
||||
model.updateById();
|
||||
}
|
||||
|
||||
public void deleteSmartCabinet(BulkOperationCommand<Long> command) {
|
||||
for (Long cabinetId : command.getIds()) {
|
||||
SmartCabinetModel model = smartCabinetModelFactory.loadById(cabinetId);
|
||||
model.deleteById();
|
||||
}
|
||||
}
|
||||
|
||||
public List<SmartCabinetEntity> selectAll() {
|
||||
return smartCabinetService.selectAll();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.command;
|
||||
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class AddSmartCabinetCommand extends SmartCabinetEntity {
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.PositiveOrZero;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class UpdateSmartCabinetCommand extends AddSmartCabinetCommand {
|
||||
|
||||
@NotNull
|
||||
@PositiveOrZero
|
||||
private Long cabinetId;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.db;
|
||||
|
||||
import com.agileboot.common.core.base.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 智能柜信息表
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2025-03-17
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("smart_cabinet")
|
||||
@ApiModel(value = "SmartCabinetEntity对象", description = "智能柜信息表")
|
||||
public class SmartCabinetEntity extends BaseEntity<SmartCabinetEntity> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("柜机唯一ID")
|
||||
@TableId(value = "cabinet_id", type = IdType.AUTO)
|
||||
private Long cabinetId;
|
||||
|
||||
@ApiModelProperty("柜机名称")
|
||||
@TableField("cabinet_name")
|
||||
private String cabinetName;
|
||||
|
||||
@ApiModelProperty("柜机类型(0主柜 1副柜)")
|
||||
@TableField("cabinet_type")
|
||||
private Integer cabinetType;
|
||||
|
||||
@ApiModelProperty("柜机模版编号")
|
||||
@TableField("template_no")
|
||||
private String templateNo;
|
||||
|
||||
@ApiModelProperty("锁控板序号")
|
||||
@TableField("lock_control_no")
|
||||
private Integer lockControlNo;
|
||||
|
||||
@ApiModelProperty("柜机位置")
|
||||
@TableField("location")
|
||||
private Integer location;
|
||||
|
||||
|
||||
@Override
|
||||
public Serializable pkVal() {
|
||||
return this.cabinetId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.db;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 智能柜信息表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2025-03-17
|
||||
*/
|
||||
public interface SmartCabinetMapper extends BaseMapper<SmartCabinetEntity> {
|
||||
@Select("SELECT cabinet_id, cabinet_name, cabinet_type, template_no, lock_control_no, location " +
|
||||
"FROM smart_cabinet " +
|
||||
"${ew.customSqlSegment}")
|
||||
Page<SmartCabinetEntity> getCabinetList(
|
||||
Page<SmartCabinetEntity> page,
|
||||
@Param(Constants.WRAPPER) Wrapper<SmartCabinetEntity> queryWrapper
|
||||
);
|
||||
|
||||
@Select("SELECT * " +
|
||||
"FROM smart_cabinet " +
|
||||
"WHERE cabinet_type = '0' " +
|
||||
"ORDER BY create_time DESC " +
|
||||
"LIMIT 1")
|
||||
SmartCabinetEntity selectFirstEnabledCabinet();
|
||||
|
||||
@Select("SELECT * " +
|
||||
"FROM smart_cabinet " +
|
||||
"WHERE cabinet_type = '0' " +
|
||||
"ORDER BY create_time DESC")
|
||||
List<SmartCabinetEntity> selectAllEnabled();
|
||||
|
||||
@Select("SELECT * FROM smart_cabinet WHERE template_no = #{templateNo} LIMIT 1")
|
||||
SmartCabinetEntity selectByTemplateNo(String templateNo);
|
||||
|
||||
@Select("SELECT * FROM smart_cabinet WHERE cabinet_name = #{cabinetName} LIMIT 1")
|
||||
SmartCabinetEntity selectByCabinetName(String cabinetName);
|
||||
|
||||
// 新增根据柜体ID查询的方法
|
||||
@Select("SELECT * FROM smart_cabinet WHERE cabinet_id = #{cabinetId} LIMIT 1")
|
||||
SmartCabinetEntity selectByCabinetId(Long cabinetId);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.db;
|
||||
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 智能柜信息表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2025-03-17
|
||||
*/
|
||||
public interface SmartCabinetService extends IService<SmartCabinetEntity> {
|
||||
|
||||
Page<SmartCabinetEntity> getCabinetList(AbstractPageQuery<SmartCabinetEntity> query);
|
||||
|
||||
List<SmartCabinetEntity> selectAll();
|
||||
|
||||
SmartCabinetEntity getFirstEnabledCabinet();
|
||||
|
||||
SmartCabinetEntity getByCabinetId(Long cabinetId);
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.db;
|
||||
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import java.util.List;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 智能柜信息表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author valarchie
|
||||
* @since 2025-03-17
|
||||
*/
|
||||
@Service
|
||||
public class SmartCabinetServiceImpl extends ServiceImpl<SmartCabinetMapper, SmartCabinetEntity> implements SmartCabinetService {
|
||||
|
||||
@Override
|
||||
public Page<SmartCabinetEntity> getCabinetList(AbstractPageQuery<SmartCabinetEntity> query) {
|
||||
return this.page(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SmartCabinetEntity> selectAll() {
|
||||
LambdaQueryWrapper<SmartCabinetEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
return this.list(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmartCabinetEntity getFirstEnabledCabinet() {
|
||||
return baseMapper.selectFirstEnabledCabinet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmartCabinetEntity getByCabinetId(Long cabinetId) {
|
||||
return baseMapper.selectByCabinetId(cabinetId);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.dto;
|
||||
|
||||
import com.agileboot.domain.cabinet.cell.dto.CabinetCellDTO;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class AllCabinetDataDTO {
|
||||
|
||||
private List<SmartCabinetDTO> smartCabinetList;
|
||||
private List<CabinetCellDTO> cells;
|
||||
|
||||
public AllCabinetDataDTO(List<SmartCabinetDTO> cabinets, List<CabinetCellDTO> cells) {
|
||||
this.smartCabinetList = cabinets;
|
||||
this.cells = cells;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.dto;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.common.annotation.ExcelColumn;
|
||||
import com.agileboot.common.annotation.ExcelSheet;
|
||||
import com.agileboot.domain.common.cache.CacheCenter;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetEntity;
|
||||
import com.agileboot.domain.system.user.db.SysUserEntity;
|
||||
import lombok.Data;
|
||||
|
||||
@ExcelSheet(name = "智能柜信息表")
|
||||
@Data
|
||||
public class SmartCabinetDTO {
|
||||
|
||||
public SmartCabinetDTO(SmartCabinetEntity entity) {
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
|
||||
/* SysUserEntity creator = CacheCenter.userCache.getObjectById(entity.getOperId());
|
||||
if (creator != null) {
|
||||
this.operator = creator.getUsername();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@ExcelColumn(name = "柜机唯一ID")
|
||||
private Long cabinetId;
|
||||
|
||||
@ExcelColumn(name = "柜机名称")
|
||||
private String cabinetName;
|
||||
|
||||
@ExcelColumn(name = "柜机类型(0主柜 1副柜)")
|
||||
private Integer cabinetType;
|
||||
|
||||
@ExcelColumn(name = "柜机模版编号")
|
||||
private String templateNo;
|
||||
|
||||
@ExcelColumn(name = "锁控板序号")
|
||||
private Integer lockControlNo;
|
||||
|
||||
@ExcelColumn(name = "柜机位置")
|
||||
private Integer location;
|
||||
|
||||
@ExcelColumn(name = "操作人")
|
||||
private String operator;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.model;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.command.AddSmartCabinetCommand;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.command.UpdateSmartCabinetCommand;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetEntity;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetService;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class SmartCabinetModel extends SmartCabinetEntity {
|
||||
|
||||
private SmartCabinetService smartCabinetService;
|
||||
|
||||
public SmartCabinetModel(SmartCabinetEntity entity, SmartCabinetService smartCabinetService) {
|
||||
this(smartCabinetService);
|
||||
if (entity != null) {
|
||||
BeanUtil.copyProperties(entity, this);
|
||||
}
|
||||
}
|
||||
|
||||
public SmartCabinetModel(SmartCabinetService smartCabinetService) {
|
||||
this.smartCabinetService = smartCabinetService;
|
||||
}
|
||||
|
||||
public void loadAddCommand(AddSmartCabinetCommand command) {
|
||||
if (command != null) {
|
||||
BeanUtil.copyProperties(command, this, "cabinetId");
|
||||
}
|
||||
}
|
||||
|
||||
public void loadUpdateCommand(UpdateSmartCabinetCommand command) {
|
||||
if (command != null) {
|
||||
loadAddCommand(command);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.model;
|
||||
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetEntity;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SmartCabinetModelFactory {
|
||||
|
||||
private final SmartCabinetService smartCabinetService;
|
||||
|
||||
public SmartCabinetModel loadById(Long cabinetId) {
|
||||
SmartCabinetEntity entity = smartCabinetService.getById(cabinetId);
|
||||
if (entity == null) {
|
||||
throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, cabinetId, "智能柜");
|
||||
}
|
||||
return new SmartCabinetModel(entity, smartCabinetService);
|
||||
}
|
||||
|
||||
public SmartCabinetModel create() {
|
||||
return new SmartCabinetModel(smartCabinetService);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.agileboot.domain.cabinet.smartCabinet.query;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.agileboot.common.core.page.AbstractPageQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class SearchSmartCabinetQuery<T> extends AbstractPageQuery<T> {
|
||||
|
||||
private String cabinetName;
|
||||
private Integer cabinetType;
|
||||
private String templateNo;
|
||||
private Date startTime;
|
||||
private Date endTime;
|
||||
|
||||
@Override
|
||||
public QueryWrapper<T> addQueryCondition() {
|
||||
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
|
||||
|
||||
queryWrapper
|
||||
.like(StrUtil.isNotEmpty(cabinetName), "cabinet_name", cabinetName)
|
||||
.eq(cabinetType != null, "cabinet_type", cabinetType)
|
||||
.eq(StrUtil.isNotEmpty(templateNo), "template_no", templateNo)
|
||||
.between(startTime != null && endTime != null, "create_time", startTime, endTime);
|
||||
|
||||
this.timeRangeColumn = "create_time";
|
||||
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.agileboot.domain.mqtt;
|
||||
|
||||
public class BCCCalculator {
|
||||
|
||||
/**
|
||||
* 计算十六进制字符串的BCC校验位(异或校验)
|
||||
* @param hexData 输入的十六进制字符串(如 "8A010011")
|
||||
* @return BCC校验位的十六进制字符串(如 "9A")
|
||||
*/
|
||||
public static String calculateBCC(String hexData) {
|
||||
// 检查输入合法性
|
||||
if (hexData == null || hexData.isEmpty()) {
|
||||
throw new IllegalArgumentException("输入不能为空");
|
||||
}
|
||||
if (hexData.length() % 2 != 0) {
|
||||
throw new IllegalArgumentException("输入的十六进制长度必须为偶数");
|
||||
}
|
||||
|
||||
// 将十六进制字符串转换为字节数组
|
||||
byte[] bytes = hexStringToByteArray(hexData);
|
||||
|
||||
// 计算异或校验
|
||||
byte bcc = 0x00; // 初始值
|
||||
for (byte b : bytes) {
|
||||
bcc ^= b;
|
||||
}
|
||||
|
||||
// 将校验位转换为十六进制字符串
|
||||
return String.format("%02X", bcc & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将十六进制字符串转换为字节数组
|
||||
*/
|
||||
public static byte[] hexStringToByteArray(String hex) {
|
||||
int len = hex.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
// 处理每两个字符为一个字节(兼容大小写)
|
||||
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
|
||||
+ Character.digit(hex.charAt(i + 1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为十六进制字符串
|
||||
* @param bytes
|
||||
* @return
|
||||
*/
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02X", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 示例:计算 "8A010011" 的BCC校验位
|
||||
String hexData = "8A010111";
|
||||
String bcc = calculateBCC(hexData);
|
||||
System.out.println("BCC校验位: " + bcc); // 输出 9A
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.agileboot.domain.mqtt;
|
||||
|
||||
import org.eclipse.paho.client.mqttv3.*;
|
||||
|
||||
public class MqttDemo {
|
||||
|
||||
private static String serverUrl = "tcp://221.7.159.46:1883";
|
||||
private static String userName = "lock";
|
||||
private static String password = "lock@ys#6785$";
|
||||
|
||||
/**
|
||||
* 将十六进制字符串转换为字节数组
|
||||
* @param hex
|
||||
* @return
|
||||
*/
|
||||
private static byte[] hexStringToBytes(String hex) {
|
||||
int len = hex.length();
|
||||
byte[] data = new byte[len / 2];
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
|
||||
+ Character.digit(hex.charAt(i + 1), 16));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换为十六进制字符串
|
||||
* @param bytes
|
||||
* @return
|
||||
*/
|
||||
private static String bytesToHex(byte[] bytes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02X", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static class AuthSubscriber implements MqttCallback {
|
||||
|
||||
@Override
|
||||
public void messageArrived(String topic, MqttMessage message) {
|
||||
System.out.println("收到消息: " + bytesToHex(message.getPayload()));
|
||||
}
|
||||
|
||||
@Override public void connectionLost(Throwable cause) {}
|
||||
@Override public void deliveryComplete(IMqttDeliveryToken token) {}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws MqttException, InterruptedException {
|
||||
MqttClient client = new MqttClient(serverUrl, "pub-client");
|
||||
|
||||
// 创建连接选项并设置账号密码
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
|
||||
options.setUserName(userName); // 用户名
|
||||
options.setPassword(password.toCharArray()); // 密码(需转为字符数组)
|
||||
|
||||
// 设置订阅回调实现
|
||||
client.setCallback(new AuthSubscriber());
|
||||
|
||||
client.connect(options); // 使用带认证的选项连接
|
||||
client.subscribe("lock/up/S4202414S"); // 订阅主题
|
||||
client.publish("lock/down/S4202414S", new MqttMessage(hexStringToBytes("8A0101119B"))); // 向主题发送数据
|
||||
|
||||
Thread.sleep(10000); // 延时,测试订阅主题收到消息
|
||||
client.disconnect();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.agileboot.domain.mqtt;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.eclipse.paho.client.mqttv3.*;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MqttService implements MqttCallback {
|
||||
private static final String SERVER_URL = "tcp://221.7.159.46:1883";
|
||||
private static final String USERNAME = "lock";
|
||||
private static final String PASSWORD = "lock@ys#6785$";
|
||||
private static final String TOPIC_FILTER = "lock/up/S4202414S";
|
||||
private static final String TOPIC = "lock/down/S4202414S";
|
||||
|
||||
private MqttClient client;
|
||||
// 设置自定义消息处理器
|
||||
@Setter
|
||||
private MessageHandler messageHandler; // 自定义消息处理器接口
|
||||
|
||||
public interface MessageHandler {
|
||||
void handleMessage(String topic, String hexPayload);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() throws MqttException {
|
||||
connect();
|
||||
subscribe(TOPIC_FILTER);
|
||||
|
||||
setMessageHandler((String topic, String hexPayload) -> {
|
||||
log.info("收到消息 topic: {}, hexPayload: {}", topic, hexPayload);
|
||||
});
|
||||
}
|
||||
|
||||
public void connect() throws MqttException {
|
||||
client = new MqttClient(SERVER_URL, MqttClient.generateClientId(), new MemoryPersistence());
|
||||
MqttConnectOptions options = new MqttConnectOptions();
|
||||
options.setUserName(USERNAME);
|
||||
options.setPassword(PASSWORD.toCharArray());
|
||||
options.setCleanSession(true);
|
||||
options.setAutomaticReconnect(true);
|
||||
|
||||
client.setCallback(this);
|
||||
client.connect(options);
|
||||
log.info("连接 MQTT 服务器 {}", SERVER_URL);
|
||||
}
|
||||
|
||||
public void subscribe(String topic) throws MqttException {
|
||||
client.subscribe(topic);
|
||||
}
|
||||
|
||||
public void publish(String data) throws MqttException {
|
||||
String bcc = BCCCalculator.calculateBCC(data);
|
||||
MqttMessage message = new MqttMessage(BCCCalculator.hexStringToByteArray(data + bcc));
|
||||
client.publish(TOPIC, message);
|
||||
}
|
||||
|
||||
public void disconnect() throws MqttException {
|
||||
client.disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageArrived(String topic, MqttMessage message) {
|
||||
if (messageHandler != null) {
|
||||
String hexString = BCCCalculator.bytesToHex(message.getPayload());
|
||||
messageHandler.handleMessage(topic, hexString);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionLost(Throwable cause) {
|
||||
System.err.println("连接丢失: " + cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliveryComplete(IMqttDeliveryToken token) {}
|
||||
}
|
|
@ -20,11 +20,8 @@ public class QyAccessTokenServiceImpl extends ServiceImpl<QyAccessTokenMapper, Q
|
|||
|
||||
@Override
|
||||
public Page<QyAccessTokenEntity> getAccessTokenList(AbstractPageQuery<QyAccessTokenEntity> query) {
|
||||
LambdaQueryWrapper<QyAccessTokenEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(QyAccessTokenEntity::getEnable, "1")
|
||||
.orderByDesc(QyAccessTokenEntity::getGettokenTime);
|
||||
|
||||
return this.page(query.toPage(), wrapper);
|
||||
return this.page(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,9 +20,8 @@ public class QyAuthServiceImpl extends ServiceImpl<QyAuthMapper, QyAuthEntity> i
|
|||
|
||||
@Override
|
||||
public Page<QyAuthEntity> getAuthList(AbstractPageQuery<QyAuthEntity> query) {
|
||||
LambdaQueryWrapper<QyAuthEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
return this.page(query.toPage(), wrapper);
|
||||
return this.page(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,8 +20,7 @@ public class QyAuthCorpInfoServiceImpl extends ServiceImpl<QyAuthCorpInfoMapper,
|
|||
|
||||
@Override
|
||||
public Page<QyAuthCorpInfoEntity> getAuthCorpInfoList(AbstractPageQuery<QyAuthCorpInfoEntity> query) {
|
||||
LambdaQueryWrapper<QyAuthCorpInfoEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
return this.page(query.toPage(), wrapper);
|
||||
return this.page(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,9 +13,8 @@ public class QyDepartmentServiceImpl extends ServiceImpl<QyDepartmentMapper, QyD
|
|||
|
||||
@Override
|
||||
public Page<QyDepartmentEntity> getDepartmentList(AbstractPageQuery<QyDepartmentEntity> query) {
|
||||
LambdaQueryWrapper<QyDepartmentEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
return this.page(query.toPage(), wrapper);
|
||||
return this.page(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -20,9 +20,7 @@ public class QyMessageServiceImpl extends ServiceImpl<QyMessageMapper, QyMessage
|
|||
|
||||
@Override
|
||||
public Page<QyMessageEntity> getMessageList(AbstractPageQuery<QyMessageEntity> query) {
|
||||
LambdaQueryWrapper<QyMessageEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
return this.page(query.toPage(), wrapper);
|
||||
return this.page(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,11 +15,7 @@ public class QyTemplateServiceImpl extends ServiceImpl<QyTemplateMapper, QyTempl
|
|||
|
||||
@Override
|
||||
public Page<QyTemplateEntity> getTemplateList(AbstractPageQuery<QyTemplateEntity> query) {
|
||||
LambdaQueryWrapper<QyTemplateEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(QyTemplateEntity::getEnable, "1")
|
||||
.orderByDesc(QyTemplateEntity::getGettokenTime);
|
||||
|
||||
return this.page(query.toPage(), wrapper);
|
||||
return this.page(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,11 +21,7 @@ public class QyUserServiceImpl extends ServiceImpl<QyUserMapper, QyUserEntity> i
|
|||
|
||||
@Override
|
||||
public Page<QyUserEntity> getUserList(AbstractPageQuery<QyUserEntity> query) {
|
||||
LambdaQueryWrapper<QyUserEntity> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(QyUserEntity::getEnable, "1")
|
||||
.orderByDesc(QyUserEntity::getId);
|
||||
|
||||
return this.page(query.toPage(), wrapper);
|
||||
return this.page(query.toPage(), query.toQueryWrapper());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.agileboot.domain.shop.goods.db;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
@ -7,5 +9,11 @@ import lombok.EqualsAndHashCode;
|
|||
@Data
|
||||
public class SearchGoodsDO extends ShopGoodsEntity {
|
||||
|
||||
@TableField("category_name")
|
||||
private String categoryName;
|
||||
|
||||
@TableField("cabinet_name")
|
||||
private String cabinetName;
|
||||
@TableField("cell_no")
|
||||
private Integer cellNo;
|
||||
}
|
||||
|
|
|
@ -24,9 +24,12 @@ public interface ShopGoodsMapper extends BaseMapper<ShopGoodsEntity> {
|
|||
* @return 商品分页列表
|
||||
*/
|
||||
@Select("SELECT g.goods_id, g.goods_name, g.category_id, g.price, " +
|
||||
"g.stock, g.status, g.cover_img, c.category_name " +
|
||||
"g.stock, g.status, g.cover_img, c.category_name, " +
|
||||
"sc.cabinet_name, cc.cell_no " +
|
||||
"FROM shop_goods g " +
|
||||
"LEFT JOIN shop_category c ON g.category_id = c.category_id " +
|
||||
"LEFT JOIN cabinet_cell cc ON g.goods_id = cc.goods_id " +
|
||||
"LEFT JOIN smart_cabinet sc ON cc.cabinet_id = sc.cabinet_id " +
|
||||
"${ew.customSqlSegment}")
|
||||
Page<SearchGoodsDO> getGoodsList(
|
||||
Page<SearchGoodsDO> page,
|
||||
|
|
|
@ -46,8 +46,8 @@ public class ShopGoodsDTO {
|
|||
@ExcelColumn(name = "分类ID")
|
||||
private Long categoryId;
|
||||
|
||||
/* @ExcelColumn(name = "分类名称")
|
||||
private String categoryName;*/
|
||||
@ExcelColumn(name = "分类名称")
|
||||
private String categoryName;
|
||||
|
||||
@ExcelColumn(name = "销售价格")
|
||||
private BigDecimal price;
|
||||
|
@ -72,4 +72,9 @@ public class ShopGoodsDTO {
|
|||
|
||||
@ExcelColumn(name = "备注")
|
||||
private String remark;
|
||||
|
||||
@ExcelColumn(name = "柜机名称")
|
||||
private String cabinetName;
|
||||
@ExcelColumn(name = "格口号")
|
||||
private Integer cellNo;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package com.agileboot.domain.shop.order;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.agileboot.common.core.page.PageDTO;
|
||||
import com.agileboot.common.exception.ApiException;
|
||||
import com.agileboot.common.exception.error.ErrorCode;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellEntity;
|
||||
import com.agileboot.domain.cabinet.cell.db.CabinetCellService;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetEntity;
|
||||
import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetService;
|
||||
import com.agileboot.domain.common.command.BulkOperationCommand;
|
||||
import com.agileboot.domain.mqtt.MqttService;
|
||||
import com.agileboot.domain.shop.goods.db.ShopGoodsEntity;
|
||||
import com.agileboot.domain.shop.goods.db.ShopGoodsService;
|
||||
import com.agileboot.domain.shop.order.command.SubmitOrderCommand;
|
||||
|
@ -14,26 +17,26 @@ import com.agileboot.domain.shop.order.db.ShopOrderService;
|
|||
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderGoodsService;
|
||||
import com.agileboot.domain.shop.order.dto.CreateOrderResult;
|
||||
import com.agileboot.domain.shop.order.dto.ShopOrderDTO;
|
||||
import com.agileboot.domain.shop.order.dto.GetOrdersByOpenIdDTO;
|
||||
import com.agileboot.domain.shop.order.model.OrderModel;
|
||||
import com.agileboot.domain.shop.order.model.OrderModelFactory;
|
||||
import com.agileboot.domain.shop.order.model.OrderGoodsModel;
|
||||
import com.agileboot.domain.shop.order.model.OrderGoodsModelFactory;
|
||||
import com.agileboot.domain.shop.order.query.SearchShopOrderQuery;
|
||||
import com.agileboot.domain.shop.payment.PaymentApplicationService;
|
||||
import com.agileboot.domain.shop.payment.dto.WxJsApiPreCreateRequest;
|
||||
import com.agileboot.domain.shop.payment.dto.WxJsApiPreCreateResponse;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class OrderApplicationService {
|
||||
|
@ -44,6 +47,9 @@ public class OrderApplicationService {
|
|||
private final OrderModelFactory orderModelFactory;
|
||||
private final OrderGoodsModelFactory orderGoodsModelFactory;
|
||||
private final PaymentApplicationService paymentApplicationService;
|
||||
private final CabinetCellService cabinetCellService;
|
||||
private final SmartCabinetService smartCabinetService;
|
||||
private final MqttService mqttService;
|
||||
|
||||
/*public PageDTO<ShopOrderDTO> getOrderList(SearchShopOrderQuery<> query) {
|
||||
Page<ShopOrderEntity> page = orderService.page(query.toPage(), query.toQueryWrapper());
|
||||
|
@ -51,6 +57,45 @@ public class OrderApplicationService {
|
|||
return new PageDTO<>(dtoList, page.getTotal());
|
||||
}*/
|
||||
|
||||
public void openOrderGoodsCabinet(Long orderId, Long orderGoodsId) {
|
||||
OrderModel orderModel = orderModelFactory.loadById(orderId);
|
||||
// 验证订单状态
|
||||
if (orderModel.getStatus() != 2) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_FORBIDDEN_TO_CALL, "订单状态不允许操作");
|
||||
}
|
||||
|
||||
ShopOrderGoodsEntity goodsEntity = orderGoodsService.getById(orderGoodsId);
|
||||
if (null == goodsEntity || !orderId.equals(goodsEntity.getOrderId())) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_FORBIDDEN_TO_CALL, "订单商品不存在");
|
||||
}
|
||||
if (goodsEntity.getStatus() != 1) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_FORBIDDEN_TO_CALL, "订单商品状态不允许操作");
|
||||
}
|
||||
|
||||
List<CabinetCellEntity> cabinetCellEntityList = cabinetCellService.selectByGoodsId(goodsEntity.getGoodsId());
|
||||
if (null == cabinetCellEntityList || cabinetCellEntityList.isEmpty()) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_FORBIDDEN_TO_CALL, "商品未绑定柜子");
|
||||
}
|
||||
CabinetCellEntity cabinetCellEntity = cabinetCellEntityList.get(0);
|
||||
|
||||
SmartCabinetEntity smartCabinet = smartCabinetService.getById(cabinetCellEntity.getCabinetId());
|
||||
if (null == smartCabinet) {
|
||||
throw new ApiException(ErrorCode.Client.COMMON_FORBIDDEN_TO_CALL, "柜子不存在");
|
||||
}
|
||||
|
||||
// 发送指令
|
||||
String mqttDate = "8A";
|
||||
mqttDate += String.format("%02X", smartCabinet.getLockControlNo());
|
||||
mqttDate += String.format("%02X", cabinetCellEntity.getPinNo());
|
||||
mqttDate += "11";
|
||||
try {
|
||||
mqttService.publish(mqttDate);
|
||||
} catch (Exception e) {
|
||||
log.error("mqtt publish error", e);
|
||||
throw new ApiException(ErrorCode.Internal.INTERNAL_ERROR, "发送指令失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CreateOrderResult createOrder(SubmitOrderCommand command) {
|
||||
List<ShopOrderGoodsEntity> goodsList = command.getGoodsList();
|
||||
|
@ -80,9 +125,9 @@ public class OrderApplicationService {
|
|||
|
||||
private WxJsApiPreCreateRequest buildPaymentRequest(OrderModel orderModel) {
|
||||
WxJsApiPreCreateRequest request = new WxJsApiPreCreateRequest();
|
||||
request.setIp("222.218.10.217");
|
||||
request.setIp("111.59.237.29");
|
||||
request.setOpenid(orderModel.getOpenid()); //
|
||||
request.setBiz_order_id(String.valueOf(orderModel.getOrderId())); // 使用订单唯一编号
|
||||
request.setBiz_order_id("wxshop-" + orderModel.getOrderId() + "-" + new Date().getTime()); // 使用订单唯一编号
|
||||
// 金额转换(元转分)并四舍五入
|
||||
BigDecimal amountInFen = orderModel.getTotalAmount()
|
||||
.multiply(new BigDecimal("100"))
|
||||
|
@ -90,7 +135,7 @@ public class OrderApplicationService {
|
|||
request.setPay_amount(amountInFen.toPlainString()); // 单位转换为分
|
||||
|
||||
request.setTitle("商品订单支付");
|
||||
request.setNotify_url("http://wxshop.ab98.cn/shop-back-end/api/payment/callback");
|
||||
request.setNotify_url("http://wxshop.ab98.cn/shop-api/api/payment/callback");
|
||||
request.setBiz_id("wxshop");
|
||||
request.setUcid(orderModel.getUcid());
|
||||
request.setExtra("");
|
||||
|
@ -171,4 +216,57 @@ public class OrderApplicationService {
|
|||
model.deleteById();
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePaymentSuccess(Long orderId, Integer amount, String tradeId, String tradePayTime) {
|
||||
OrderModel orderModel = orderModelFactory.loadById(orderId);
|
||||
// 状态校验
|
||||
orderModel.validateStatusTransition(2); // 2代表已支付
|
||||
// 更新订单状态
|
||||
orderModel.setStatus(2);
|
||||
orderModel.setPayStatus(2);
|
||||
orderModel.setTradeId(tradeId);
|
||||
try {
|
||||
// if (tradePayTime.contains("+")) {
|
||||
// tradePayTime = tradePayTime.replace("+", " ");
|
||||
// }
|
||||
orderModel.setPayTime(DateUtil.parse(tradePayTime));
|
||||
} catch (Exception e) {
|
||||
log.error("支付时间转换失败", e);
|
||||
}
|
||||
orderModel.updateById();
|
||||
|
||||
QueryWrapper<ShopOrderGoodsEntity> orderGoodsQueryWrapper = new QueryWrapper<>();
|
||||
orderGoodsQueryWrapper.eq("order_id", orderId);
|
||||
List<ShopOrderGoodsEntity> orderGoods = orderGoodsService.list(orderGoodsQueryWrapper);
|
||||
|
||||
// 发送指令
|
||||
orderGoods.forEach(g -> {
|
||||
openOrderGoodsCabinet(orderId, g.getOrderGoodsId());
|
||||
});
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[] testCases = {0, 15, 22, 255, 256, -1}; // 包含边界值、正常值、超范围值和负数
|
||||
|
||||
for (int num : testCases) {
|
||||
String hex = String.format("%02X", num);
|
||||
System.out.println(num + " → " + hex);
|
||||
}
|
||||
}
|
||||
|
||||
public GetOrdersByOpenIdDTO getOrdersByOpenId(String openid) {
|
||||
QueryWrapper<ShopOrderEntity> orderQueryWrapper = new QueryWrapper<>();
|
||||
orderQueryWrapper.eq("openid", openid);
|
||||
List<ShopOrderEntity> orderList = orderService.list(orderQueryWrapper);
|
||||
|
||||
QueryWrapper<ShopOrderGoodsEntity> orderGoodsQueryWrapper = new QueryWrapper<>();
|
||||
orderGoodsQueryWrapper.in("order_id", orderList.stream().map(ShopOrderEntity::getOrderId).collect(Collectors.toList()));
|
||||
List<ShopOrderGoodsEntity> orderGoods = orderGoodsService.list(orderGoodsQueryWrapper);
|
||||
|
||||
QueryWrapper<ShopGoodsEntity> goodsQueryWrapper = new QueryWrapper<>();
|
||||
goodsQueryWrapper.in("goods_id", orderGoods.stream().map(ShopOrderGoodsEntity::getGoodsId).collect(Collectors.toList()));
|
||||
List<ShopGoodsEntity> goods = goodsService.list(goodsQueryWrapper);
|
||||
|
||||
return new GetOrdersByOpenIdDTO(orderList, orderGoods, goods);
|
||||
}
|
||||
}
|
|
@ -52,7 +52,7 @@ public class ShopOrderGoodsEntity extends BaseEntity<ShopOrderGoodsEntity> {
|
|||
@TableField("total_amount")
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
@ApiModelProperty("商品状态(1正常 2已退货 3已换货)")
|
||||
@ApiModelProperty("商品状态(1正常 2已退货 3已换货 4已完成)")
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package com.agileboot.domain.shop.order.dto;
|
||||
|
||||
import com.agileboot.domain.shop.goods.db.ShopGoodsEntity;
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderEntity;
|
||||
import com.agileboot.domain.shop.order.db.ShopOrderGoodsEntity;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class GetOrdersByOpenIdDTO {
|
||||
List<ShopOrderEntity> orders;
|
||||
List<ShopOrderGoodsEntity> orderGoods;
|
||||
List<ShopGoodsEntity> goods;
|
||||
}
|
|
@ -7,10 +7,13 @@ import cn.hutool.http.HttpUtil;
|
|||
import cn.hutool.json.JSONUtil;
|
||||
import com.agileboot.domain.shop.payment.dto.WxJsApiPreCreateRequest;
|
||||
import com.agileboot.domain.shop.payment.dto.WxJsApiPreCreateResponse;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PaymentApplicationService {
|
||||
|
@ -19,6 +22,7 @@ public class PaymentApplicationService {
|
|||
|
||||
try {
|
||||
String jsonBody = JSONUtil.toJsonStr(request);
|
||||
log.info("callJsApiPreCreate 请求body:{}", jsonBody);
|
||||
|
||||
// 使用try-with-resources自动关闭连接
|
||||
try (HttpResponse httpResponse = HttpUtil.createPost(gatewayUrl)
|
||||
|
@ -30,6 +34,7 @@ public class PaymentApplicationService {
|
|||
// 获取HTTP状态码和响应体
|
||||
int status = httpResponse.getStatus();
|
||||
String result = httpResponse.body();
|
||||
log.info("callJsApiPreCreate 响应body:{}", result);
|
||||
|
||||
// 先校验HTTP状态码
|
||||
if (status != HttpStatus.HTTP_OK) {
|
||||
|
@ -41,7 +46,8 @@ public class PaymentApplicationService {
|
|||
throw new RuntimeException("支付网关返回非JSON格式响应:" + result);
|
||||
}
|
||||
|
||||
WxJsApiPreCreateResponse response = JSONUtil.toBean(result, WxJsApiPreCreateResponse.class);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
WxJsApiPreCreateResponse response = mapper.readValue(result, WxJsApiPreCreateResponse.class);
|
||||
if (response.getAppId() != null) {
|
||||
return response;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?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="com.agileboot.domain.cabinet.cell.db.CabinetCellMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,5 @@
|
|||
<?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="com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetMapper">
|
||||
|
||||
</mapper>
|
|
@ -61,7 +61,7 @@ public class CodeGenerator {
|
|||
//生成的类 放在orm子模块下的/target/generated-code目录底下
|
||||
.module("/agileboot-orm/target/generated-code")
|
||||
.parentPackage("com.agileboot")
|
||||
.tableName("qy_user")
|
||||
.tableName("cabinet_cell")
|
||||
// 决定是否继承基类
|
||||
.isExtendsFromBaseEntity(true)
|
||||
.build();
|
||||
|
|
1
pom.xml
1
pom.xml
|
@ -47,6 +47,7 @@
|
|||
<maven.compiler.plugin.version>3.1</maven.compiler.plugin.version>
|
||||
<maven.surefire.plugin.version>2.5</maven.surefire.plugin.version>
|
||||
<maven.war.plugin.version>3.1.0</maven.war.plugin.version>
|
||||
<mqttv3.version>1.2.5</mqttv3.version>
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
DROP TABLE IF EXISTS `smart_cabinet`;
|
||||
|
||||
CREATE TABLE `smart_cabinet` (
|
||||
`cabinet_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '柜机唯一ID',
|
||||
`cabinet_name` VARCHAR(100) NOT NULL COMMENT '柜机名称',
|
||||
`cabinet_type` TINYINT NOT NULL DEFAULT 0 COMMENT '柜机类型(0主柜 1副柜)',
|
||||
`template_no` VARCHAR(50) NOT NULL COMMENT '柜机模版编号',
|
||||
`lock_control_no` INT NOT NULL COMMENT '锁控板序号',
|
||||
`location` INT NOT NULL COMMENT '柜机位置',
|
||||
`creator_id` BIGINT NOT NULL DEFAULT 0 COMMENT '创建者ID',
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater_id` BIGINT NOT NULL DEFAULT 0 COMMENT '更新者ID',
|
||||
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标志(0存在 1删除)',
|
||||
PRIMARY KEY (`cabinet_id`),
|
||||
KEY `idx_template_no` (`template_no`),
|
||||
KEY `idx_location` (`location`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='智能柜信息表';
|
||||
|
||||
DROP TABLE IF EXISTS `cabinet_cell`;
|
||||
|
||||
CREATE TABLE `cabinet_cell` (
|
||||
`cell_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '格口唯一ID',
|
||||
`cabinet_id` BIGINT NOT NULL COMMENT '关联柜机ID',
|
||||
`goods_id` BIGINT DEFAULT NULL COMMENT '关联商品ID',
|
||||
`cell_no` INT NOT NULL COMMENT '格口号',
|
||||
`pin_no` INT NOT NULL COMMENT '针脚序号',
|
||||
`cell_type` TINYINT NOT NULL DEFAULT 1 COMMENT '格口类型(1小格 2中格 3大格 4超大格)',
|
||||
`usage_status` TINYINT NOT NULL DEFAULT 1 COMMENT '使用状态(1空闲 2已占用)',
|
||||
`available_status` TINYINT NOT NULL DEFAULT 1 COMMENT '可用状态(1正常 2故障)',
|
||||
`creator_id` BIGINT NOT NULL DEFAULT 0 COMMENT '创建者ID',
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater_id` BIGINT NOT NULL DEFAULT 0 COMMENT '更新者ID',
|
||||
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '删除标志(0存在 1删除)',
|
||||
PRIMARY KEY (`cell_id`),
|
||||
KEY `idx_cabinet` (`cabinet_id`),
|
||||
KEY `idx_usage_status` (`usage_status`),
|
||||
KEY `idx_available_status` (`available_status`),
|
||||
KEY `idx_goods` (`goods_id`),
|
||||
CONSTRAINT `fk_cell_cabinet` FOREIGN KEY (`cabinet_id`) REFERENCES `smart_cabinet` (`cabinet_id`),
|
||||
CONSTRAINT `fk_cell_goods` FOREIGN KEY (`goods_id`) REFERENCES `shop_goods` (`goods_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='柜机格口信息表';
|
||||
|
||||
INSERT INTO sys_menu
|
||||
(menu_name, menu_type, router_name, parent_id, `path`, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted)
|
||||
VALUES('柜机管理', 2, '', 0, '/cabinet', 0, '', '{"title":"柜机管理","icon":"fa-solid:server","showLink":true,"showParent":true,"rank":2}', 1, '', 1, '2025-03-17 17:55:52', NULL, NULL, 0);
|
||||
INSERT INTO sys_menu
|
||||
(menu_name, menu_type, router_name, parent_id, `path`, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted)
|
||||
VALUES('柜机列表', 1, 'SmartCabinet', 69, '/cabinet/smart-cabinet/index', 0, '', '{"title":"柜机列表","showLink":true,"showParent":true,"rank":1}', 1, '', 1, '2025-03-17 17:58:10', 1, '2025-03-17 17:58:21', 0);
|
||||
INSERT INTO sys_menu
|
||||
(menu_name, menu_type, router_name, parent_id, `path`, is_button, permission, meta_info, status, remark, creator_id, create_time, updater_id, update_time, deleted)
|
||||
VALUES('格口管理', 1, 'CabinetCell', 69, '/cabinet/cabinet-cell/index', 0, '', '{"title":"格口管理","showParent":true,"rank":2}', 1, '', 1, '2025-03-18 17:23:47', NULL, NULL, 0);
|
Loading…
Reference in New Issue