From 48e1b88c220790846bbb53c49554ee36ec7276e6 Mon Sep 17 00:00:00 2001 From: dqz Date: Fri, 21 Mar 2025 16:59:17 +0800 Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=99=BA=E8=83=BD=E6=9F=9C?= =?UTF-8?q?=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cabinet/CabinetCellController.java | 76 ++++++++++++ .../cabinet/SmartCabinetController.java | 90 ++++++++++++++ .../controller/common/TestController.java | 55 +++++++++ .../qywx/QyDepartmentController.java | 21 ++++ .../customize/config/SecurityConfig.java | 2 +- .../customize/service/QywxScheduleJob.java | 64 +++++++--- .../api/controller/MonitorController.java | 41 +++++++ .../api/controller/MqttController.java | 32 +++++ .../api/controller/OrderController.java | 15 +++ .../api/controller/PaymentController.java | 31 +++-- .../api/controller/ShopController.java | 19 +++ .../common/constant/WeixinConstants.java | 6 +- .../agileboot/common/utils/OpenSignUtil.java | 37 +++++- agileboot-domain/pom.xml | 5 + .../cell/CabinetCellApplicationService.java | 72 +++++++++++ .../cell/command/AddCabinetCellCommand.java | 11 ++ .../command/UpdateCabinetCellCommand.java | 16 +++ .../cabinet/cell/db/CabinetCellEntity.java | 68 ++++++++++ .../cabinet/cell/db/CabinetCellMapper.java | 47 +++++++ .../cabinet/cell/db/CabinetCellService.java | 23 ++++ .../cell/db/CabinetCellServiceImpl.java | 36 ++++++ .../cabinet/cell/dto/CabinetCellDTO.java | 78 ++++++++++++ .../cabinet/cell/model/CabinetCellModel.java | 41 +++++++ .../cell/model/CabinetCellModelFactory.java | 27 ++++ .../cell/query/SearchCabinetCellQuery.java | 40 ++++++ .../SmartCabinetApplicationService.java | 55 +++++++++ .../command/AddSmartCabinetCommand.java | 11 ++ .../command/UpdateSmartCabinetCommand.java | 15 +++ .../smartCabinet/db/SmartCabinetEntity.java | 60 +++++++++ .../smartCabinet/db/SmartCabinetMapper.java | 50 ++++++++ .../smartCabinet/db/SmartCabinetService.java | 26 ++++ .../db/SmartCabinetServiceImpl.java | 42 +++++++ .../smartCabinet/dto/AllCabinetDataDTO.java | 17 +++ .../smartCabinet/dto/SmartCabinetDTO.java | 46 +++++++ .../smartCabinet/model/SmartCabinetModel.java | 39 ++++++ .../model/SmartCabinetModelFactory.java | 27 ++++ .../query/SearchSmartCabinetQuery.java | 34 +++++ .../agileboot/domain/mqtt/BCCCalculator.java | 65 ++++++++++ .../com/agileboot/domain/mqtt/MqttDemo.java | 71 +++++++++++ .../agileboot/domain/mqtt/MqttService.java | 82 +++++++++++++ .../db/QyAccessTokenServiceImpl.java | 5 +- .../qywx/auth/db/QyAuthServiceImpl.java | 3 +- .../db/QyAuthCorpInfoServiceImpl.java | 3 +- .../db/QyDepartmentServiceImpl.java | 3 +- .../qywx/message/db/QyMessageServiceImpl.java | 4 +- .../template/db/QyTemplateServiceImpl.java | 6 +- .../qywx/user/db/QyUserServiceImpl.java | 6 +- .../domain/shop/goods/db/SearchGoodsDO.java | 8 ++ .../domain/shop/goods/db/ShopGoodsMapper.java | 5 +- .../domain/shop/goods/dto/ShopGoodsDTO.java | 9 +- .../shop/order/OrderApplicationService.java | 116 ++++++++++++++++-- .../shop/order/db/ShopOrderGoodsEntity.java | 2 +- .../shop/order/dto/GetOrdersByOpenIdDTO.java | 16 +++ .../payment/PaymentApplicationService.java | 8 +- .../mapper/cabinet/CabinetCellMapper.xml | 5 + .../mapper/cabinet/SmartCabinetMapper.xml | 5 + .../mybatisplus/CodeGenerator.java | 2 +- pom.xml | 1 + sql/20250317.sql | 53 ++++++++ 59 files changed, 1782 insertions(+), 71 deletions(-) create mode 100644 agileboot-admin/src/main/java/com/agileboot/admin/controller/cabinet/CabinetCellController.java create mode 100644 agileboot-admin/src/main/java/com/agileboot/admin/controller/cabinet/SmartCabinetController.java create mode 100644 agileboot-admin/src/main/java/com/agileboot/admin/controller/common/TestController.java create mode 100644 agileboot-api/src/main/java/com/agileboot/api/controller/MqttController.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/CabinetCellApplicationService.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/AddCabinetCellCommand.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/UpdateCabinetCellCommand.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellEntity.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellMapper.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellService.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellServiceImpl.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/dto/CabinetCellDTO.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModel.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModelFactory.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/query/SearchCabinetCellQuery.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/SmartCabinetApplicationService.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/command/AddSmartCabinetCommand.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/command/UpdateSmartCabinetCommand.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetEntity.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetMapper.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetService.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetServiceImpl.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/dto/AllCabinetDataDTO.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/dto/SmartCabinetDTO.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/model/SmartCabinetModel.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/model/SmartCabinetModelFactory.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/query/SearchSmartCabinetQuery.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/mqtt/BCCCalculator.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/mqtt/MqttDemo.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/mqtt/MqttService.java create mode 100644 agileboot-domain/src/main/java/com/agileboot/domain/shop/order/dto/GetOrdersByOpenIdDTO.java create mode 100644 agileboot-domain/src/main/resources/mapper/cabinet/CabinetCellMapper.xml create mode 100644 agileboot-domain/src/main/resources/mapper/cabinet/SmartCabinetMapper.xml create mode 100644 sql/20250317.sql diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/controller/cabinet/CabinetCellController.java b/agileboot-admin/src/main/java/com/agileboot/admin/controller/cabinet/CabinetCellController.java new file mode 100644 index 0000000..d855883 --- /dev/null +++ b/agileboot-admin/src/main/java/com/agileboot/admin/controller/cabinet/CabinetCellController.java @@ -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> list(SearchCabinetCellQuery query) { + PageDTO page = cabinetCellApplicationService.getCabinetCellList(query); + return ResponseDTO.ok(page); + } + + @Operation(summary = "新增格口") + @AccessLog(title = "格口管理", businessType = BusinessTypeEnum.ADD) + @PostMapping + public ResponseDTO add(@Validated @RequestBody AddCabinetCellCommand command) { + cabinetCellApplicationService.addCabinetCell(command); + return ResponseDTO.ok(); + } + + @Operation(summary = "修改格口") + @AccessLog(title = "格口管理", businessType = BusinessTypeEnum.MODIFY) + @PutMapping("/{cellId}") + public ResponseDTO 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 remove(@PathVariable @NotNull List ids) { + cabinetCellApplicationService.deleteCabinetCell(new BulkOperationCommand<>(ids)); + return ResponseDTO.ok(); + } + + @Operation(summary = "配置格口商品") + @AccessLog(title = "格口管理", businessType = BusinessTypeEnum.MODIFY) + @PutMapping("/configureGoodsCells/{cellId}/{goodsId}") + public ResponseDTO configureGoodsCells(@PathVariable Long cellId, @PathVariable Long goodsId) { + cabinetCellApplicationService.configureGoodsCells(cellId, goodsId); + return ResponseDTO.ok(); + } +} \ No newline at end of file diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/controller/cabinet/SmartCabinetController.java b/agileboot-admin/src/main/java/com/agileboot/admin/controller/cabinet/SmartCabinetController.java new file mode 100644 index 0000000..097f988 --- /dev/null +++ b/agileboot-admin/src/main/java/com/agileboot/admin/controller/cabinet/SmartCabinetController.java @@ -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> list(SearchSmartCabinetQuery query) { + PageDTO page = smartCabinetApplicationService.getSmartCabinetList(query); + return ResponseDTO.ok(page); + } + + @Operation(summary = "新增智能柜") + @AccessLog(title = "智能柜管理", businessType = BusinessTypeEnum.ADD) + @PostMapping + public ResponseDTO add(@Validated @RequestBody AddSmartCabinetCommand command) { + smartCabinetApplicationService.addSmartCabinet(command); + return ResponseDTO.ok(); + } + + @Operation(summary = "修改智能柜") + @AccessLog(title = "智能柜管理", businessType = BusinessTypeEnum.MODIFY) + @PutMapping("/{id}") + public ResponseDTO 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 remove(@PathVariable @NotNull List ids) { + smartCabinetApplicationService.deleteSmartCabinet(new BulkOperationCommand<>(ids)); + return ResponseDTO.ok(); + } + + + @Operation(summary = "获取所有柜机和格口数据") + @GetMapping("/all") + public ResponseDTO getAllCabinetsWithCells() { + List cells = cabinetCellApplicationService.selectAll().stream() + .filter(cell -> cell.getAvailableStatus().equals(1) && cell.getUsageStatus().equals(1)) + .map(CabinetCellDTO::new) + .collect(Collectors.toList()); + + List 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)); + } +} \ No newline at end of file diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/TestController.java b/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/TestController.java new file mode 100644 index 0000000..6ea79be --- /dev/null +++ b/agileboot-admin/src/main/java/com/agileboot/admin/controller/common/TestController.java @@ -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(); + } + } +} diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/controller/qywx/QyDepartmentController.java b/agileboot-admin/src/main/java/com/agileboot/admin/controller/qywx/QyDepartmentController.java index 455f35f..db0fba8 100644 --- a/agileboot-admin/src/main/java/com/agileboot/admin/controller/qywx/QyDepartmentController.java +++ b/agileboot-admin/src/main/java/com/agileboot/admin/controller/qywx/QyDepartmentController.java @@ -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(); + } + } } \ No newline at end of file diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/customize/config/SecurityConfig.java b/agileboot-admin/src/main/java/com/agileboot/admin/customize/config/SecurityConfig.java index d5d1fb7..be9dda3 100644 --- a/agileboot-admin/src/main/java/com/agileboot/admin/customize/config/SecurityConfig.java +++ b/agileboot-admin/src/main/java/com/agileboot/admin/customize/config/SecurityConfig.java @@ -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() diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/QywxScheduleJob.java b/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/QywxScheduleJob.java index 2cbcc3a..ceead50 100644 --- a/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/QywxScheduleJob.java +++ b/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/QywxScheduleJob.java @@ -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 newDeptList = toAdd.stream() + List 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 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 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); } } } + diff --git a/agileboot-api/src/main/java/com/agileboot/api/controller/MonitorController.java b/agileboot-api/src/main/java/com/agileboot/api/controller/MonitorController.java index f23d22e..15f4c08 100644 --- a/agileboot-api/src/main/java/com/agileboot/api/controller/MonitorController.java +++ b/agileboot-api/src/main/java/com/agileboot/api/controller/MonitorController.java @@ -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(); + } + } } diff --git a/agileboot-api/src/main/java/com/agileboot/api/controller/MqttController.java b/agileboot-api/src/main/java/com/agileboot/api/controller/MqttController.java new file mode 100644 index 0000000..8eb2b91 --- /dev/null +++ b/agileboot-api/src/main/java/com/agileboot/api/controller/MqttController.java @@ -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(); + } + } +} diff --git a/agileboot-api/src/main/java/com/agileboot/api/controller/OrderController.java b/agileboot-api/src/main/java/com/agileboot/api/controller/OrderController.java index ecb28ab..f909623 100644 --- a/agileboot-api/src/main/java/com/agileboot/api/controller/OrderController.java +++ b/agileboot-api/src/main/java/com/agileboot/api/controller/OrderController.java @@ -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 getOrdersByOpenId(@PathVariable String openid) { + GetOrdersByOpenIdDTO result = orderApplicationService.getOrdersByOpenId(openid); + return ResponseDTO.ok(result); + } } diff --git a/agileboot-api/src/main/java/com/agileboot/api/controller/PaymentController.java b/agileboot-api/src/main/java/com/agileboot/api/controller/PaymentController.java index b1e2d14..df802fd 100644 --- a/agileboot-api/src/main/java/com/agileboot/api/controller/PaymentController.java +++ b/agileboot-api/src/main/java/com/agileboot/api/controller/PaymentController.java @@ -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); + } } } diff --git a/agileboot-api/src/main/java/com/agileboot/api/controller/ShopController.java b/agileboot-api/src/main/java/com/agileboot/api/controller/ShopController.java index 07f198c..68f2807 100644 --- a/agileboot-api/src/main/java/com/agileboot/api/controller/ShopController.java +++ b/agileboot-api/src/main/java/com/agileboot/api/controller/ShopController.java @@ -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 getShopGoodsInfo() { // 获取商品列表 List goodsList = goodsApplicationService.getGoodsAll(); + goodsList.forEach(goods -> { + // 最多只能购买一件 + if (!goods.getStock().equals(0)) { + goods.setStock(1); + } + }); // 获取分类列表 List 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); + } } \ No newline at end of file diff --git a/agileboot-common/src/main/java/com/agileboot/common/constant/WeixinConstants.java b/agileboot-common/src/main/java/com/agileboot/common/constant/WeixinConstants.java index 2f3f377..5970a0a 100644 --- a/agileboot-common/src/main/java/com/agileboot/common/constant/WeixinConstants.java +++ b/agileboot-common/src/main/java/com/agileboot/common/constant/WeixinConstants.java @@ -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"; } diff --git a/agileboot-common/src/main/java/com/agileboot/common/utils/OpenSignUtil.java b/agileboot-common/src/main/java/com/agileboot/common/utils/OpenSignUtil.java index 7189e16..baa5067 100644 --- a/agileboot-common/src/main/java/com/agileboot/common/utils/OpenSignUtil.java +++ b/agileboot-common/src/main/java/com/agileboot/common/utils/OpenSignUtil.java @@ -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 getKVList(Map sortedParams) { - return sortedParams.entrySet().stream() - .map(entry -> entry.getKey() + "=" + entry.getValue()) - .collect(Collectors.toList()); + public static List getKVList(Map params) { + if(MapUtils.isEmpty(params)) { + return Collections.emptyList(); + } + List 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 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); + } } diff --git a/agileboot-domain/pom.xml b/agileboot-domain/pom.xml index e954716..1e73d05 100644 --- a/agileboot-domain/pom.xml +++ b/agileboot-domain/pom.xml @@ -35,6 +35,11 @@ + + org.eclipse.paho + org.eclipse.paho.client.mqttv3 + 1.2.5 + diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/CabinetCellApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/CabinetCellApplicationService.java new file mode 100644 index 0000000..089b9b7 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/CabinetCellApplicationService.java @@ -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 getCabinetCellList(SearchCabinetCellQuery query) { + Page page = cabinetCellService.getCellList(query); + List 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 command) { + for (Long cellId : command.getIds()) { + CabinetCellModel model = cabinetCellModelFactory.loadById(cellId); + model.deleteById(); + } + } + + public List selectAll() { + return cabinetCellService.selectAll(); + } + + public void configureGoodsCells(Long cellId, Long goodsId) { + List 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(); + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/AddCabinetCellCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/AddCabinetCellCommand.java new file mode 100644 index 0000000..6ba7070 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/AddCabinetCellCommand.java @@ -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 { + +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/UpdateCabinetCellCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/UpdateCabinetCellCommand.java new file mode 100644 index 0000000..3f37990 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/UpdateCabinetCellCommand.java @@ -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; + +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellEntity.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellEntity.java new file mode 100644 index 0000000..88cc4e6 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellEntity.java @@ -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; + +/** + *

+ * 柜机格口信息表 + *

+ * + * @author valarchie + * @since 2025-03-17 + */ +@Getter +@Setter +@TableName("cabinet_cell") +@ApiModel(value = "CabinetCellEntity对象", description = "柜机格口信息表") +public class CabinetCellEntity extends BaseEntity { + + 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; + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellMapper.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellMapper.java new file mode 100644 index 0000000..6bfe9b3 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellMapper.java @@ -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; + +/** + *

+ * 柜机格口信息表 Mapper 接口 + *

+ * + * @author valarchie + * @since 2025-03-17 + */ +public interface CabinetCellMapper extends BaseMapper { + + @Select("SELECT * " + + "FROM cabinet_cell " + + "${ew.customSqlSegment}") + Page getCellList( + Page page, + @Param(Constants.WRAPPER) Wrapper 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 selectAll(); + + @Select("SELECT * " + + "FROM cabinet_cell " + + "WHERE goods_id = #{goodsId} " + + "ORDER BY cell_id DESC") + List selectByGoodsId(@Param("goodsId")Long goodsId); +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellService.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellService.java new file mode 100644 index 0000000..a78d211 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellService.java @@ -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; + +/** + *

+ * 柜机格口信息表 服务类 + *

+ * + * @author valarchie + * @since 2025-03-17 + */ +public interface CabinetCellService extends IService { + + Page getCellList(AbstractPageQuery query); + + List selectAll(); + + List selectByGoodsId(Long goodsId); +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellServiceImpl.java new file mode 100644 index 0000000..a7611ba --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellServiceImpl.java @@ -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; + +/** + *

+ * 柜机格口信息表 服务实现类 + *

+ * + * @author valarchie + * @since 2025-03-17 + */ +@Service +public class CabinetCellServiceImpl extends ServiceImpl implements CabinetCellService { + + @Override + public Page getCellList(AbstractPageQuery query) { + return baseMapper.getCellList(query.toPage(), query.toQueryWrapper()); + } + + @Override + public List selectAll() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + return this.list(wrapper); + } + + @Override + public List selectByGoodsId(Long goodsId) { + return baseMapper.selectByGoodsId(goodsId); + } +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/dto/CabinetCellDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/dto/CabinetCellDTO.java new file mode 100644 index 0000000..0db69ac --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/dto/CabinetCellDTO.java @@ -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 "未知类型"; + } + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModel.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModel.java new file mode 100644 index 0000000..be57322 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModel.java @@ -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); + } + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModelFactory.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModelFactory.java new file mode 100644 index 0000000..21313fb --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModelFactory.java @@ -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); + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/query/SearchCabinetCellQuery.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/query/SearchCabinetCellQuery.java new file mode 100644 index 0000000..26a1fd8 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/query/SearchCabinetCellQuery.java @@ -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 extends AbstractPageQuery { + + 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 addQueryCondition() { + QueryWrapper 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; + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/SmartCabinetApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/SmartCabinetApplicationService.java new file mode 100644 index 0000000..65f322e --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/SmartCabinetApplicationService.java @@ -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 getSmartCabinetList(SearchSmartCabinetQuery query) { + Page page = smartCabinetService.getCabinetList(query); + List 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 command) { + for (Long cabinetId : command.getIds()) { + SmartCabinetModel model = smartCabinetModelFactory.loadById(cabinetId); + model.deleteById(); + } + } + + public List selectAll() { + return smartCabinetService.selectAll(); + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/command/AddSmartCabinetCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/command/AddSmartCabinetCommand.java new file mode 100644 index 0000000..7fcc568 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/command/AddSmartCabinetCommand.java @@ -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 { + +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/command/UpdateSmartCabinetCommand.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/command/UpdateSmartCabinetCommand.java new file mode 100644 index 0000000..fdd68b5 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/command/UpdateSmartCabinetCommand.java @@ -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; +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetEntity.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetEntity.java new file mode 100644 index 0000000..2e69236 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetEntity.java @@ -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; + +/** + *

+ * 智能柜信息表 + *

+ * + * @author valarchie + * @since 2025-03-17 + */ +@Getter +@Setter +@TableName("smart_cabinet") +@ApiModel(value = "SmartCabinetEntity对象", description = "智能柜信息表") +public class SmartCabinetEntity extends BaseEntity { + + 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; + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetMapper.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetMapper.java new file mode 100644 index 0000000..fdde72c --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetMapper.java @@ -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; + +/** + *

+ * 智能柜信息表 Mapper 接口 + *

+ * + * @author valarchie + * @since 2025-03-17 + */ +public interface SmartCabinetMapper extends BaseMapper { + @Select("SELECT cabinet_id, cabinet_name, cabinet_type, template_no, lock_control_no, location " + + "FROM smart_cabinet " + + "${ew.customSqlSegment}") + Page getCabinetList( + Page page, + @Param(Constants.WRAPPER) Wrapper 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 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); +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetService.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetService.java new file mode 100644 index 0000000..e9a9df6 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetService.java @@ -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; + +/** + *

+ * 智能柜信息表 服务类 + *

+ * + * @author valarchie + * @since 2025-03-17 + */ +public interface SmartCabinetService extends IService { + + Page getCabinetList(AbstractPageQuery query); + + List selectAll(); + + SmartCabinetEntity getFirstEnabledCabinet(); + + SmartCabinetEntity getByCabinetId(Long cabinetId); + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetServiceImpl.java new file mode 100644 index 0000000..f156e71 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/db/SmartCabinetServiceImpl.java @@ -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; + +/** + *

+ * 智能柜信息表 服务实现类 + *

+ * + * @author valarchie + * @since 2025-03-17 + */ +@Service +public class SmartCabinetServiceImpl extends ServiceImpl implements SmartCabinetService { + + @Override + public Page getCabinetList(AbstractPageQuery query) { + return this.page(query.toPage(), query.toQueryWrapper()); + } + + @Override + public List selectAll() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + return this.list(wrapper); + } + + @Override + public SmartCabinetEntity getFirstEnabledCabinet() { + return baseMapper.selectFirstEnabledCabinet(); + } + + @Override + public SmartCabinetEntity getByCabinetId(Long cabinetId) { + return baseMapper.selectByCabinetId(cabinetId); + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/dto/AllCabinetDataDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/dto/AllCabinetDataDTO.java new file mode 100644 index 0000000..47912b8 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/dto/AllCabinetDataDTO.java @@ -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 smartCabinetList; + private List cells; + + public AllCabinetDataDTO(List cabinets, List cells) { + this.smartCabinetList = cabinets; + this.cells = cells; + } +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/dto/SmartCabinetDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/dto/SmartCabinetDTO.java new file mode 100644 index 0000000..99a8014 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/dto/SmartCabinetDTO.java @@ -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; +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/model/SmartCabinetModel.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/model/SmartCabinetModel.java new file mode 100644 index 0000000..7600f6a --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/model/SmartCabinetModel.java @@ -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); + } + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/model/SmartCabinetModelFactory.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/model/SmartCabinetModelFactory.java new file mode 100644 index 0000000..b8b91f6 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/model/SmartCabinetModelFactory.java @@ -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); + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/query/SearchSmartCabinetQuery.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/query/SearchSmartCabinetQuery.java new file mode 100644 index 0000000..02a6a5c --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/query/SearchSmartCabinetQuery.java @@ -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 extends AbstractPageQuery { + + private String cabinetName; + private Integer cabinetType; + private String templateNo; + private Date startTime; + private Date endTime; + + @Override + public QueryWrapper addQueryCondition() { + QueryWrapper 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; + } +} \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/BCCCalculator.java b/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/BCCCalculator.java new file mode 100644 index 0000000..4489abc --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/BCCCalculator.java @@ -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 + } +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/MqttDemo.java b/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/MqttDemo.java new file mode 100644 index 0000000..22f8179 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/MqttDemo.java @@ -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(); + } + +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/MqttService.java b/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/MqttService.java new file mode 100644 index 0000000..5e7a196 --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/mqtt/MqttService.java @@ -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) {} +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/accessToken/db/QyAccessTokenServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/accessToken/db/QyAccessTokenServiceImpl.java index 3b818f6..579b62a 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/accessToken/db/QyAccessTokenServiceImpl.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/accessToken/db/QyAccessTokenServiceImpl.java @@ -20,11 +20,8 @@ public class QyAccessTokenServiceImpl extends ServiceImpl getAccessTokenList(AbstractPageQuery query) { - LambdaQueryWrapper 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 diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/auth/db/QyAuthServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/auth/db/QyAuthServiceImpl.java index 7582a97..30a9f3e 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/auth/db/QyAuthServiceImpl.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/auth/db/QyAuthServiceImpl.java @@ -20,9 +20,8 @@ public class QyAuthServiceImpl extends ServiceImpl i @Override public Page getAuthList(AbstractPageQuery query) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - return this.page(query.toPage(), wrapper); + return this.page(query.toPage(), query.toQueryWrapper()); } @Override diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/authCorpInfo/db/QyAuthCorpInfoServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/authCorpInfo/db/QyAuthCorpInfoServiceImpl.java index 3fadf22..7f56bfb 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/authCorpInfo/db/QyAuthCorpInfoServiceImpl.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/authCorpInfo/db/QyAuthCorpInfoServiceImpl.java @@ -20,8 +20,7 @@ public class QyAuthCorpInfoServiceImpl extends ServiceImpl getAuthCorpInfoList(AbstractPageQuery query) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - return this.page(query.toPage(), wrapper); + return this.page(query.toPage(), query.toQueryWrapper()); } @Override diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/department/db/QyDepartmentServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/department/db/QyDepartmentServiceImpl.java index 3dba3d9..d6c726f 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/department/db/QyDepartmentServiceImpl.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/department/db/QyDepartmentServiceImpl.java @@ -13,9 +13,8 @@ public class QyDepartmentServiceImpl extends ServiceImpl getDepartmentList(AbstractPageQuery query) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - return this.page(query.toPage(), wrapper); + return this.page(query.toPage(), query.toQueryWrapper()); } @Override diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/message/db/QyMessageServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/message/db/QyMessageServiceImpl.java index 8660471..2e63ca1 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/message/db/QyMessageServiceImpl.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/message/db/QyMessageServiceImpl.java @@ -20,9 +20,7 @@ public class QyMessageServiceImpl extends ServiceImpl getMessageList(AbstractPageQuery query) { - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - - return this.page(query.toPage(), wrapper); + return this.page(query.toPage(), query.toQueryWrapper()); } @Override diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/template/db/QyTemplateServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/template/db/QyTemplateServiceImpl.java index 0accd40..9e624a3 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/template/db/QyTemplateServiceImpl.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/template/db/QyTemplateServiceImpl.java @@ -15,11 +15,7 @@ public class QyTemplateServiceImpl extends ServiceImpl getTemplateList(AbstractPageQuery query) { - LambdaQueryWrapper 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 diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/user/db/QyUserServiceImpl.java b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/user/db/QyUserServiceImpl.java index 02a0a58..c4a52d9 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/qywx/user/db/QyUserServiceImpl.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/qywx/user/db/QyUserServiceImpl.java @@ -21,11 +21,7 @@ public class QyUserServiceImpl extends ServiceImpl i @Override public Page getUserList(AbstractPageQuery query) { - LambdaQueryWrapper 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 diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/SearchGoodsDO.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/SearchGoodsDO.java index 3af909e..1e14f20 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/SearchGoodsDO.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/SearchGoodsDO.java @@ -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; } diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/ShopGoodsMapper.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/ShopGoodsMapper.java index 18da2cb..69e4572 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/ShopGoodsMapper.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/ShopGoodsMapper.java @@ -24,9 +24,12 @@ public interface ShopGoodsMapper extends BaseMapper { * @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 getGoodsList( Page page, diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/dto/ShopGoodsDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/dto/ShopGoodsDTO.java index 27348c5..b6de37e 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/dto/ShopGoodsDTO.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/dto/ShopGoodsDTO.java @@ -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; } diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java index 9496d54..b9da32a 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java @@ -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 getOrderList(SearchShopOrderQuery<> query) { Page 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 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 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 orderGoodsQueryWrapper = new QueryWrapper<>(); + orderGoodsQueryWrapper.eq("order_id", orderId); + List 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 orderQueryWrapper = new QueryWrapper<>(); + orderQueryWrapper.eq("openid", openid); + List orderList = orderService.list(orderQueryWrapper); + + QueryWrapper orderGoodsQueryWrapper = new QueryWrapper<>(); + orderGoodsQueryWrapper.in("order_id", orderList.stream().map(ShopOrderEntity::getOrderId).collect(Collectors.toList())); + List orderGoods = orderGoodsService.list(orderGoodsQueryWrapper); + + QueryWrapper goodsQueryWrapper = new QueryWrapper<>(); + goodsQueryWrapper.in("goods_id", orderGoods.stream().map(ShopOrderGoodsEntity::getGoodsId).collect(Collectors.toList())); + List goods = goodsService.list(goodsQueryWrapper); + + return new GetOrdersByOpenIdDTO(orderList, orderGoods, goods); + } } \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/db/ShopOrderGoodsEntity.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/db/ShopOrderGoodsEntity.java index 5afab56..96dc3c2 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/db/ShopOrderGoodsEntity.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/db/ShopOrderGoodsEntity.java @@ -52,7 +52,7 @@ public class ShopOrderGoodsEntity extends BaseEntity { @TableField("total_amount") private BigDecimal totalAmount; - @ApiModelProperty("商品状态(1正常 2已退货 3已换货)") + @ApiModelProperty("商品状态(1正常 2已退货 3已换货 4已完成)") @TableField("`status`") private Integer status; diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/dto/GetOrdersByOpenIdDTO.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/dto/GetOrdersByOpenIdDTO.java new file mode 100644 index 0000000..85189bd --- /dev/null +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/dto/GetOrdersByOpenIdDTO.java @@ -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 orders; + List orderGoods; + List goods; +} diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/payment/PaymentApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/payment/PaymentApplicationService.java index 78f6f04..7c559b0 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/payment/PaymentApplicationService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/payment/PaymentApplicationService.java @@ -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; } diff --git a/agileboot-domain/src/main/resources/mapper/cabinet/CabinetCellMapper.xml b/agileboot-domain/src/main/resources/mapper/cabinet/CabinetCellMapper.xml new file mode 100644 index 0000000..030398d --- /dev/null +++ b/agileboot-domain/src/main/resources/mapper/cabinet/CabinetCellMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/agileboot-domain/src/main/resources/mapper/cabinet/SmartCabinetMapper.xml b/agileboot-domain/src/main/resources/mapper/cabinet/SmartCabinetMapper.xml new file mode 100644 index 0000000..dada7fa --- /dev/null +++ b/agileboot-domain/src/main/resources/mapper/cabinet/SmartCabinetMapper.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/mybatisplus/CodeGenerator.java b/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/mybatisplus/CodeGenerator.java index d97fe95..09b0cc5 100644 --- a/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/mybatisplus/CodeGenerator.java +++ b/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/mybatisplus/CodeGenerator.java @@ -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(); diff --git a/pom.xml b/pom.xml index 3c3e902..e47dd97 100644 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,7 @@ 3.1 2.5 3.1.0 + 1.2.5 diff --git a/sql/20250317.sql b/sql/20250317.sql new file mode 100644 index 0000000..aee9e68 --- /dev/null +++ b/sql/20250317.sql @@ -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); \ No newline at end of file