mirror of
https://gitee.com/yudaocode/yudao-boot-mini.git
synced 2026-03-22 05:27:15 +08:00
Merge branch 'master' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-module-ai/pom.xml # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.http # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageRespVO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageSendReqVO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/vo/message/AiChatMessageSendRespVO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleRespVO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveMyReqVO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveReqVO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/chat/AiChatMessageDO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiToolDO.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/enums/model/AiPlatformEnum.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/AiAutoConfiguration.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/config/YudaoAiProperties.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactory.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/AiModelFactoryImpl.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/doubao/DouBaoChatModel.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/hunyuan/HunYuanChatModel.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/siliconflow/SiliconFlowChatModel.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/xinghuo/XingHuoChatModel.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/framework/security/config/SecurityConfiguration.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/knowledge/AiKnowledgeSegmentServiceImpl.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiModelServiceImpl.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiToolServiceImpl.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/tool/function/DirectoryListToolFunction.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/tool/function/UserProfileQueryToolFunction.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/tool/function/WeatherQueryToolFunction.java # yudao-module-ai/src/main/java/cn/iocoder/yudao/module/ai/util/AiUtils.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DeepSeekChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/DouBaoChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/HunYuanChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/LlamaChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MiniMaxChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/MoonshotChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/OpenAIChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/SiliconFlowChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/TongYiChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/XingHuoChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/chat/ZhiPuAiChatModelTests.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/image/TongYiImagesModelTest.java # yudao-module-ai/src/test/java/cn/iocoder/yudao/module/ai/framework/ai/core/model/mcp/DouBaoMcpTests.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/api/event/BpmProcessInstanceStatusEvent.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelMetaInfoVO.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/definition/BpmProcessDefinitionInfoDO.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/behavior/BpmSequentialMultiInstanceBehavior.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java # yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java # yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/customer/CrmCustomerImportExcelVO.java # yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/LogRecordConstants.java # yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/clue/CrmClueServiceImpl.java # yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java # yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/local/LocalFileClientTest.java # yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/framework/file/core/s3/S3FileClientTest.java # yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/file/FileConfigServiceImplTest.java # yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_erp/java/InfraStudentServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_inner/java/InfraStudentServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue2_master_normal/java/InfraStudentServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue2_one/java/InfraStudentServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue2_tree/java/InfraCategoryServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue3_master_erp/java/InfraStudentServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue3_master_inner/java/InfraStudentServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue3_master_normal/java/InfraStudentServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue3_one/java/InfraStudentServiceImplTest # yudao-module-infra/src/test/resources/codegen/windows10/vue3_tree/java/InfraCategoryServiceImplTest # yudao-module-iot/pom.xml # yudao-module-iot/yudao-module-iot-biz/pom.xml # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyHistoryListReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/property/IotDevicePropertyRespVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/task/IotOtaTaskCreateReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductRespVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/product/IotProductSaveReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/data/sink/IotDataSinkPageReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/statistics/IotStatisticsController.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.http # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/IotThingModelController.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thingmodel/IotThingModelConvert.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertConfigDO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/alert/IotAlertRecordDO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/product/IotProductDO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotDataSinkDO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkHttpConfig.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkKafkaConfig.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkMqttConfig.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRabbitMQConfig.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/config/IotDataSinkRocketMQConfig.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/IotThingModelDO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelEvent.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelParam.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelProperty.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/ThingModelService.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelArrayDataSpecs.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDataSpecs.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelDateOrTextDataSpecs.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelNumericDataSpec.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/thingmodel/model/dataType/ThingModelStructDataSpecs.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/thingmodel/IotThingModelMapper.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DevicePropertyRedisDAO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/device/DeviceReportTimeRedisDAO.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/tdengine/IotDevicePropertyMapper.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/alert/IotAlertReceiveTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskDeviceScopeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaTaskStatusEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotLocationTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRedisDataStructureEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionOperatorEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/config/TDengineTableInitRunner.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/tdengine/core/TDengineTableField.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/device/IotDeviceOfflineCheckJob.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/producer/package-info.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/property/IotDevicePropertyServiceImpl.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductCategoryServiceImpl.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotDataRuleCacheableAction.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotHttpDataSinkAction.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/data/action/IotKafkaDataRuleAction.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelService.java # yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java # yudao-module-iot/yudao-module-iot-biz/src/main/resources/mapper/device/IotDevicePropertyMapper.xml # yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotDataBridgeExecuteTest.java # yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/biz/dto/IotDeviceAuthReqDTO.java # yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceStateEnum.java # yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/convert/coupon/CouponConvert.java # yudao-module-mall/yudao-module-promotion/src/main/java/cn/iocoder/yudao/module/promotion/service/coupon/CouponServiceImpl.java # yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/aftersale/AfterSaleDO.java # yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/cart/CartDO.java # yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/dal/dataobject/order/TradeOrderItemDO.java # yudao-module-mall/yudao-module-trade/src/main/java/cn/iocoder/yudao/module/trade/service/order/handler/TradeStatusSyncToWxaOrderHandler.java # yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsSendReqVO.java # yudao-module-member/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthSmsValidateReqVO.java # yudao-module-member/src/test/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceTest.java # yudao-module-mp/src/main/java/cn/iocoder/yudao/module/mp/controller/admin/message/vo/message/MpMessagePageReqVO.java # yudao-module-mp/src/main/java/cn/iocoder/yudao/module/mp/dal/mysql/message/MpMessageMapper.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitReqVO.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitRespVO.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/dto/refund/PayRefundUnifiedReqDTO.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java # yudao-module-pay/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java # yudao-module-pay/src/test/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceTest.java # yudao-module-pay/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java # yudao-module-pay/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailLogServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/mail/MailSendServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2TokenServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/permission/RoleServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsChannelServiceTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsLogServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsSendServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/sms/SmsTemplateServiceImplTest.java # yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImplTest.java # yudao-module-system/src/test/resources/sql/create_tables.sql
This commit is contained in:
@@ -21,13 +21,15 @@ public class MailSendApiImpl implements MailSendApi {
|
||||
|
||||
@Override
|
||||
public Long sendSingleMailToAdmin(MailSendSingleToUserReqDTO reqDTO) {
|
||||
return mailSendService.sendSingleMailToAdmin(reqDTO.getMail(), reqDTO.getUserId(),
|
||||
return mailSendService.sendSingleMailToAdmin(reqDTO.getUserId(),
|
||||
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
|
||||
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long sendSingleMailToMember(MailSendSingleToUserReqDTO reqDTO) {
|
||||
return mailSendService.sendSingleMailToMember(reqDTO.getMail(), reqDTO.getUserId(),
|
||||
return mailSendService.sendSingleMailToMember(reqDTO.getUserId(),
|
||||
reqDTO.getToMails(), reqDTO.getCcMails(), reqDTO.getBccMails(),
|
||||
reqDTO.getTemplateCode(), reqDTO.getTemplateParams());
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -16,13 +17,24 @@ public class MailSendSingleToUserReqDTO {
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 如果非空,则加载对应用户的邮箱,添加到 {@link #toMails} 中
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 邮箱
|
||||
* 收件邮箱
|
||||
*/
|
||||
@Email
|
||||
private String mail;
|
||||
private List<@Email String> toMails;
|
||||
/**
|
||||
* 抄送邮箱
|
||||
*/
|
||||
private List<@Email String> ccMails;
|
||||
/**
|
||||
* 密送邮箱
|
||||
*/
|
||||
private List<@Email String> bccMails;
|
||||
|
||||
|
||||
/**
|
||||
* 邮件模板编号
|
||||
|
||||
@@ -11,6 +11,24 @@ tag: Yunai.local
|
||||
"code": "1024"
|
||||
}
|
||||
|
||||
### 请求 /login 接口【加密 AES】 => 成功
|
||||
POST {{baseUrl}}/system/auth/login
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
tag: Yunai.local
|
||||
X-API-ENCRYPT: true
|
||||
|
||||
WvSX9MOrenyGfBhEM0g1/hHgq8ocktMZ9OwAJ6MOG5FUrzYF/rG5JF1eMptQM1wT73VgDS05l/37WeRtad+JrqChAul/sR/SdOsUKqjBhvvQx1JVhzxr6s8uUP67aKTSZ6Psv7O32ELxXrzSaQvG5CInzz3w6sLtbNNLd1kXe6Q=
|
||||
|
||||
### 请求 /login 接口【加密 RSA】 => 成功
|
||||
POST {{baseUrl}}/system/auth/login
|
||||
Content-Type: application/json
|
||||
tenant-id: {{adminTenantId}}
|
||||
tag: Yunai.local
|
||||
X-API-ENCRYPT: true
|
||||
|
||||
e7QZTork9ZV5CmgZvSd+cHZk3xdUxKtowLM02kOha+gxHK2H/daU8nVBYS3+bwuDRy5abf+Pz1QJJGVAEd27wwrXBmupOOA/bhpuzzDwcRuJRD+z+YgiNoEXFDRHERxPYlPqAe9zAHtihD0ceub1AjybQsEsROew4C3Q602XYW0=
|
||||
|
||||
### 请求 /login 接口 => 成功(无验证码)
|
||||
POST {{baseUrl}}/system/auth/login
|
||||
Content-Type: application/json
|
||||
|
||||
@@ -56,6 +56,15 @@ public class DeptController {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-list")
|
||||
@Operation(summary = "批量删除部门")
|
||||
@Parameter(name = "ids", description = "编号列表", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:delete')")
|
||||
public CommonResult<Boolean> deleteDeptList(@RequestParam("ids") List<Long> ids) {
|
||||
deptService.deleteDeptList(ids);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获取部门列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:dept:query')")
|
||||
|
||||
@@ -91,7 +91,8 @@ public class MailTemplateController {
|
||||
@Operation(summary = "发送短信")
|
||||
@PreAuthorize("@ss.hasPermission('system:mail-template:send-mail')")
|
||||
public CommonResult<Long> sendMail(@Valid @RequestBody MailTemplateSendReqVO sendReqVO) {
|
||||
return success(mailSendService.sendSingleMailToAdmin(sendReqVO.getMail(), getLoginUserId(),
|
||||
return success(mailSendService.sendSingleMailToAdmin(getLoginUserId(),
|
||||
sendReqVO.getToMails(), sendReqVO.getCcMails(), sendReqVO.getBccMails(),
|
||||
sendReqVO.getTemplateCode(), sendReqVO.getTemplateParams()));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,11 @@ package cn.iocoder.yudao.module.system.controller.admin.mail.vo.log;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - 邮件日志 Response VO")
|
||||
@Data
|
||||
public class MailLogRespVO {
|
||||
@@ -22,8 +20,14 @@ public class MailLogRespVO {
|
||||
@Schema(description = "用户类型,参见 UserTypeEnum 枚举", example = "2")
|
||||
private Byte userType;
|
||||
|
||||
@Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "76854@qq.com")
|
||||
private String toMail;
|
||||
@Schema(description = "接收邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user1@example.com, user2@example.com")
|
||||
private List<String> toMails;
|
||||
|
||||
@Schema(description = "抄送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user3@example.com, user4@example.com")
|
||||
private List<String> ccMails;
|
||||
|
||||
@Schema(description = "密送邮箱地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "user5@example.com, user6@example.com")
|
||||
private List<String> bccMails;
|
||||
|
||||
@Schema(description = "邮箱账号编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18107")
|
||||
private Long accountId;
|
||||
|
||||
@@ -5,15 +5,22 @@ import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - 邮件发送 Req VO")
|
||||
@Data
|
||||
public class MailTemplateSendReqVO {
|
||||
|
||||
@Schema(description = "接收邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "7685413@qq.com")
|
||||
@Schema(description = "接收邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user1@example.com, user2@example.com]")
|
||||
@NotEmpty(message = "接收邮箱不能为空")
|
||||
private String mail;
|
||||
private List<String> toMails;
|
||||
|
||||
@Schema(description = "抄送邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user3@example.com, user4@example.com]")
|
||||
private List<String> ccMails;
|
||||
|
||||
@Schema(description = "密送邮箱", requiredMode = Schema.RequiredMode.REQUIRED, example = "[user5@example.com, user6@example.com]")
|
||||
private List<String> bccMails;
|
||||
|
||||
@Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "test_01")
|
||||
@NotNull(message = "模板编码不能为空")
|
||||
|
||||
@@ -35,6 +35,14 @@ tenant-id: {{adminTenantId}}
|
||||
|
||||
grant_type=password&username=admin&password=admin123&scope=user.read
|
||||
|
||||
### 请求 /system/oauth2/token + client_credentials 接口 => 成功
|
||||
POST {{baseUrl}}/system/oauth2/token
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
grant_type=client_credentials&scope=user.read
|
||||
|
||||
### 请求 /system/oauth2/token + refresh_token 接口 => 成功
|
||||
POST {{baseUrl}}/system/oauth2/token
|
||||
Content-Type: application/x-www-form-urlencoded
|
||||
|
||||
@@ -94,6 +94,7 @@ public class OAuth2OpenController {
|
||||
@Parameter(name = "scope", example = "user_info"),
|
||||
@Parameter(name = "refresh_token", example = "123424233"),
|
||||
})
|
||||
@SuppressWarnings("EnhancedSwitchMigration")
|
||||
public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request,
|
||||
@RequestParam("grant_type") String grantType,
|
||||
@RequestParam(value = "code", required = false) String code, // 授权码模式
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 租户 Response VO")
|
||||
@Data
|
||||
@@ -36,8 +37,8 @@ public class TenantRespVO {
|
||||
@DictFormat(DictTypeConstants.COMMON_STATUS)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "绑定域名", example = "https://www.iocoder.cn")
|
||||
private String website;
|
||||
@Schema(description = "绑定域名数组", example = "https://www.iocoder.cn")
|
||||
private List<String> websites;
|
||||
|
||||
@Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long packageId;
|
||||
|
||||
@@ -11,6 +11,7 @@ import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - 租户创建/修改 Request VO")
|
||||
@Data
|
||||
@@ -34,8 +35,8 @@ public class TenantSaveReqVO {
|
||||
@NotNull(message = "租户状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "绑定域名", example = "https://www.iocoder.cn")
|
||||
private String website;
|
||||
@Schema(description = "绑定域名数组", example = "https://www.iocoder.cn")
|
||||
private List<String> websites;
|
||||
|
||||
@Schema(description = "租户套餐编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "租户套餐编号不能为空")
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.user.vo.user;
|
||||
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 用户 Excel 导入 VO
|
||||
@@ -17,7 +16,6 @@ import lombok.experimental.Accessors;
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
|
||||
public class UserImportExcelVO {
|
||||
|
||||
@ExcelProperty("登录名称")
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package cn.iocoder.yudao.module.system.controller.app.tenant;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.system.controller.app.tenant.vo.AppTenantRespVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
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;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.annotation.security.PermitAll;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "用户 App - 租户")
|
||||
@RestController
|
||||
@RequestMapping("/system/tenant")
|
||||
public class AppTenantController {
|
||||
|
||||
@Resource
|
||||
private TenantService tenantService;
|
||||
|
||||
@GetMapping("/get-by-website")
|
||||
@PermitAll
|
||||
@TenantIgnore
|
||||
@Operation(summary = "使用域名,获得租户信息", description = "根据用户的域名,获得租户信息")
|
||||
@Parameter(name = "website", description = "域名", required = true, example = "www.iocoder.cn")
|
||||
public CommonResult<AppTenantRespVO> getTenantByWebsite(@RequestParam("website") String website) {
|
||||
TenantDO tenant = tenantService.getTenantByWebsite(website);
|
||||
if (tenant == null || CommonStatusEnum.isDisable(tenant.getStatus())) {
|
||||
return success(null);
|
||||
}
|
||||
return success(BeanUtils.toBean(tenant, AppTenantRespVO.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package cn.iocoder.yudao.module.system.controller.app.tenant.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "用户 App - 租户 Response VO")
|
||||
@Data
|
||||
public class AppTenantRespVO {
|
||||
|
||||
@Schema(description = "租户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "租户名", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
|
||||
private String name;
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.dataobject.mail;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.system.enums.mail.MailSendStatusEnum;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
@@ -12,6 +13,7 @@ import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -47,10 +49,22 @@ public class MailLogDO extends BaseDO implements Serializable {
|
||||
* 枚举 {@link UserTypeEnum}
|
||||
*/
|
||||
private Integer userType;
|
||||
|
||||
/**
|
||||
* 接收邮箱地址
|
||||
*/
|
||||
private String toMail;
|
||||
@TableField(typeHandler = StringListTypeHandler.class)
|
||||
private List<String> toMails;
|
||||
/**
|
||||
* 接收邮箱地址
|
||||
*/
|
||||
@TableField(typeHandler = StringListTypeHandler.class)
|
||||
private List<String> ccMails;
|
||||
/**
|
||||
* 密送邮箱地址
|
||||
*/
|
||||
@TableField(typeHandler = StringListTypeHandler.class)
|
||||
private List<String> bccMails;
|
||||
|
||||
/**
|
||||
* 邮箱账号编号
|
||||
|
||||
@@ -7,8 +7,6 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
@@ -22,8 +20,6 @@ import java.util.List;
|
||||
// 由于 Oracle 的 SEQ 的名字长度有限制,所以就先用 system_oauth2_access_token_seq 吧,反正也没啥问题
|
||||
@KeySequence("system_oauth2_access_token_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2RefreshTokenDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,13 +2,16 @@ package cn.iocoder.yudao.module.system.dal.dataobject.tenant;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.type.StringListTypeHandler;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户 DO
|
||||
@@ -60,9 +63,13 @@ public class TenantDO extends BaseDO {
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 绑定域名
|
||||
* 绑定域名列表
|
||||
*
|
||||
* 1. 考虑到对微信小程序的兼容,也允许传递 appid
|
||||
* 2. 为什么是数组,考虑到管理后台、会员前台都有独立的域名,又或者多个管理后台
|
||||
*/
|
||||
private String website;
|
||||
@TableField(typeHandler = StringListTypeHandler.class)
|
||||
private List<String> websites;
|
||||
/**
|
||||
* 租户套餐编号
|
||||
*
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package cn.iocoder.yudao.module.system.dal.mysql.mail;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@@ -14,11 +16,12 @@ public interface MailLogMapper extends BaseMapperX<MailLogDO> {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<MailLogDO>()
|
||||
.eqIfPresent(MailLogDO::getUserId, reqVO.getUserId())
|
||||
.eqIfPresent(MailLogDO::getUserType, reqVO.getUserType())
|
||||
.likeIfPresent(MailLogDO::getToMail, reqVO.getToMail())
|
||||
.eqIfPresent(MailLogDO::getAccountId, reqVO.getAccountId())
|
||||
.eqIfPresent(MailLogDO::getTemplateId, reqVO.getTemplateId())
|
||||
.eqIfPresent(MailLogDO::getSendStatus, reqVO.getSendStatus())
|
||||
.betweenIfPresent(MailLogDO::getSendTime, reqVO.getSendTime())
|
||||
.apply(StrUtil.isNotBlank(reqVO.getToMail()),
|
||||
MyBatisUtils.findInSet("to_mails", reqVO.getToMail()))
|
||||
.orderByDesc(MailLogDO::getId));
|
||||
}
|
||||
|
||||
|
||||
@@ -22,4 +22,8 @@ public interface SmsLogMapper extends BaseMapperX<SmsLogDO> {
|
||||
.orderByDesc(SmsLogDO::getId));
|
||||
}
|
||||
|
||||
default SmsLogDO selectByApiSerialNo(String apiSerialNo) {
|
||||
return selectOne(SmsLogDO::getApiSerialNo, apiSerialNo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,17 +3,13 @@ package cn.iocoder.yudao.module.system.dal.mysql.tenant;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.tenant.vo.tenant.TenantPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户 Mapper
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Mapper
|
||||
public interface TenantMapper extends BaseMapperX<TenantDO> {
|
||||
|
||||
@@ -31,8 +27,9 @@ public interface TenantMapper extends BaseMapperX<TenantDO> {
|
||||
return selectOne(TenantDO::getName, name);
|
||||
}
|
||||
|
||||
default TenantDO selectByWebsite(String website) {
|
||||
return selectOne(TenantDO::getWebsite, website);
|
||||
default List<TenantDO> selectListByWebsite(String website) {
|
||||
return selectList(new LambdaQueryWrapperX<TenantDO>()
|
||||
.apply(MyBatisUtils.findInSet("websites", website)));
|
||||
}
|
||||
|
||||
default Long selectCountByPackageId(Long packageId) {
|
||||
|
||||
@@ -9,11 +9,6 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户套餐 Mapper
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Mapper
|
||||
public interface TenantPackageMapper extends BaseMapperX<TenantPackageDO> {
|
||||
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
package cn.iocoder.yudao.module.system.framework.captcha.core;
|
||||
|
||||
import com.anji.captcha.model.common.RepCodeEnum;
|
||||
import com.anji.captcha.model.common.ResponseModel;
|
||||
import com.anji.captcha.model.vo.CaptchaVO;
|
||||
import com.anji.captcha.service.impl.AbstractCaptchaService;
|
||||
import com.anji.captcha.service.impl.CaptchaServiceFactory;
|
||||
import com.anji.captcha.util.AESUtil;
|
||||
import com.anji.captcha.util.ImageUtils;
|
||||
import com.anji.captcha.util.RandomUtils;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import org.apache.commons.lang3.Strings;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 图片文字验证码
|
||||
*
|
||||
* @author Tsui
|
||||
* @since 2025/7/23 20:44
|
||||
*/
|
||||
public class PictureWordCaptchaServiceImpl extends AbstractCaptchaService {
|
||||
|
||||
/**
|
||||
* 验证码的基础字符
|
||||
*/
|
||||
private static final String CHARACTERS = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
/**
|
||||
* 验证码长度
|
||||
*/
|
||||
private static final Integer LENGTH = 4;
|
||||
|
||||
private static final int WIDTH = 120;
|
||||
private static final int HEIGHT = 40;
|
||||
private static final int LINES = 10;
|
||||
|
||||
@Override
|
||||
public void init(Properties config) {
|
||||
super.init(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy(Properties config) {
|
||||
logger.info("start-clear-history-data-{}", captchaType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String captchaType() {
|
||||
return "pictureWord";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseModel get(CaptchaVO captchaVO) {
|
||||
String text = generateRandomText(LENGTH);
|
||||
CaptchaVO imageData = getImageData(text);
|
||||
// pointJson 不传到前端,只做后端校验,测试时放开
|
||||
// imageData.setPointJson(text);
|
||||
return ResponseModel.successData(imageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseModel check(CaptchaVO captchaVO) {
|
||||
ResponseModel r = super.check(captchaVO);
|
||||
if (!validatedReq(r)) {
|
||||
return r;
|
||||
}
|
||||
|
||||
// 取出验证码
|
||||
String codeKey = String.format(REDIS_CAPTCHA_KEY, captchaVO.getToken());
|
||||
if (!CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
|
||||
return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);
|
||||
}
|
||||
// 正确的验证码
|
||||
String codeValue = CaptchaServiceFactory.getCache(cacheType).get(codeKey);
|
||||
String code = getCodeByCodeValue(codeValue);
|
||||
String secretKey = getSecretKeyByCodeValue(codeValue);
|
||||
// 验证码只用一次,即刻失效
|
||||
CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
|
||||
|
||||
// 用户输入的验证码(CaptchaVO 中 没有预留字段,暂时用 pointJson 无需加解密)
|
||||
String userCode = captchaVO.getPointJson();
|
||||
if (!Strings.CI.equals(code, userCode)) {
|
||||
afterValidateFail(captchaVO);
|
||||
return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_COORDINATE_ERROR);
|
||||
}
|
||||
|
||||
// 校验成功,将信息存入缓存
|
||||
String value;
|
||||
try {
|
||||
value = AESUtil.aesEncrypt(captchaVO.getToken().concat("---").concat(userCode), secretKey);
|
||||
} catch (Exception e) {
|
||||
logger.error("AES 加密失败", e);
|
||||
afterValidateFail(captchaVO);
|
||||
return ResponseModel.errorMsg(e.getMessage());
|
||||
}
|
||||
String secondKey = String.format(REDIS_SECOND_CAPTCHA_KEY, value);
|
||||
CaptchaServiceFactory.getCache(cacheType).set(secondKey, captchaVO.getToken(), EXPIRESIN_THREE);
|
||||
captchaVO.setResult(true);
|
||||
captchaVO.resetClientFlag();
|
||||
return ResponseModel.successData(captchaVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseModel verification(CaptchaVO captchaVO) {
|
||||
ResponseModel r = super.verification(captchaVO);
|
||||
if (!validatedReq(r)) {
|
||||
return r;
|
||||
}
|
||||
try {
|
||||
String codeKey = String.format(REDIS_SECOND_CAPTCHA_KEY, captchaVO.getCaptchaVerification());
|
||||
if (!CaptchaServiceFactory.getCache(cacheType).exists(codeKey)) {
|
||||
return ResponseModel.errorMsg(RepCodeEnum.API_CAPTCHA_INVALID);
|
||||
}
|
||||
// 二次校验取值后,即刻失效
|
||||
CaptchaServiceFactory.getCache(cacheType).delete(codeKey);
|
||||
} catch (Exception e) {
|
||||
logger.error("验证码解析失败", e);
|
||||
return ResponseModel.errorMsg(e.getMessage());
|
||||
}
|
||||
return ResponseModel.success();
|
||||
}
|
||||
|
||||
|
||||
private CaptchaVO getImageData(String text) {
|
||||
CaptchaVO dataVO = new CaptchaVO();
|
||||
BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g = image.createGraphics();
|
||||
|
||||
// 设置背景色
|
||||
g.setColor(getRandomColor(200, 250));
|
||||
g.fillRect(0, 0, WIDTH, HEIGHT);
|
||||
// 绘制干扰线
|
||||
for (int i = 0; i < LINES; i++) {
|
||||
g.setColor(getRandomColor(100, 200));
|
||||
int x1 = RandomUtil.randomInt(WIDTH);
|
||||
int y1 = RandomUtil.randomInt(HEIGHT);
|
||||
int x2 = RandomUtil.randomInt(WIDTH);
|
||||
int y2 = RandomUtil.randomInt(HEIGHT);
|
||||
g.drawLine(x1, y1, x2, y2);
|
||||
}
|
||||
// 设置字体
|
||||
g.setFont(new Font("Arial", Font.BOLD, 24));
|
||||
// 绘制验证码文本
|
||||
for (int i = 0; i < text.length(); i++) {
|
||||
g.setColor(getRandomColor(20, 130));
|
||||
// 文字旋转
|
||||
AffineTransform affineTransform = new AffineTransform();
|
||||
int x = 20 + i * 20;
|
||||
int y = 24 + RandomUtil.randomInt(8);
|
||||
// 旋转范围 -45 ~ 45
|
||||
affineTransform.setToRotation(Math.toRadians(RandomUtil.randomInt(-45, 45)), x, y);
|
||||
g.setTransform(affineTransform);
|
||||
g.drawString(text.charAt(i) + "", x, y);
|
||||
}
|
||||
// 添加噪点
|
||||
for (int i = 0; i < 100; i++) {
|
||||
int x = RandomUtil.randomInt(WIDTH);
|
||||
int y = RandomUtil.randomInt(HEIGHT);
|
||||
image.setRGB(x, y, getRandomColor(0, 255).getRGB());
|
||||
}
|
||||
g.dispose();
|
||||
|
||||
String secretKey = null;
|
||||
if (captchaAesStatus) {
|
||||
secretKey = AESUtil.getKey();
|
||||
}
|
||||
dataVO.setSecretKey(secretKey);
|
||||
|
||||
dataVO.setOriginalImageBase64(ImageUtils.getImageToBase64Str(image).replaceAll("\r|\n", ""));
|
||||
dataVO.setToken(RandomUtils.getUUID());
|
||||
// dataVO.setSecretKey(secretKey);
|
||||
// 将坐标信息存入 redis 中
|
||||
String codeKey = String.format(REDIS_CAPTCHA_KEY, dataVO.getToken());
|
||||
CaptchaServiceFactory.getCache(cacheType).set(codeKey, getCodeValue(text, secretKey), EXPIRESIN_SECONDS);
|
||||
return dataVO;
|
||||
}
|
||||
|
||||
private String getCodeValue(String text, String secretKey) {
|
||||
return text + "," + secretKey;
|
||||
}
|
||||
|
||||
private String getCodeByCodeValue(String codeValue) {
|
||||
return codeValue.split(",")[0];
|
||||
}
|
||||
|
||||
private String getSecretKeyByCodeValue(String codeValue) {
|
||||
return codeValue.split(",")[1];
|
||||
}
|
||||
|
||||
private Color getRandomColor(int min, int max) {
|
||||
int minVal = Math.min(min, max);
|
||||
int maxVal = Math.max(min, max);
|
||||
int r = RandomUtil.randomInt(minVal, maxVal);
|
||||
int g = RandomUtil.randomInt(minVal, maxVal);
|
||||
int b = RandomUtil.randomInt(minVal, maxVal);
|
||||
return new Color(r, g, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定长度的随机字符串
|
||||
*
|
||||
* @param length 长度
|
||||
* @return {@link String}
|
||||
*/
|
||||
public static String generateRandomText(int length) {
|
||||
return RandomUtil.randomString(CHARACTERS, length);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,7 +78,6 @@ public class AuthRequestFactory {
|
||||
.keySet()
|
||||
.stream()
|
||||
.filter(x -> names.contains(x.toUpperCase()))
|
||||
.map(String::toUpperCase)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -318,4 +317,4 @@ public class AuthRequestFactory {
|
||||
.proxy(new Proxy(Proxy.Type.valueOf(proxyConfig.getType()), new InetSocketAddress(proxyConfig.getHostname(), proxyConfig.getPort())))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -113,6 +111,7 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@SuppressWarnings("EnhancedSwitchMigration")
|
||||
Integer convertSmsTemplateAuditStatus(Integer templateStatus) {
|
||||
switch (templateStatus) {
|
||||
case 0: return SmsTemplateAuditStatusEnum.CHECKING.getStatus();
|
||||
@@ -136,20 +135,25 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
.map(entry -> percentCode(entry.getKey()) + "=" + percentCode(String.valueOf(entry.getValue())))
|
||||
.collect(Collectors.joining("&"));
|
||||
|
||||
// 2.1 请求 Header
|
||||
// 2. 请求 Body
|
||||
String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空
|
||||
String hashedRequestPayload = DigestUtil.sha256Hex(requestBody);
|
||||
|
||||
// 3.1 请求 Header
|
||||
TreeMap<String, String> headers = new TreeMap<>();
|
||||
headers.put("host", HOST);
|
||||
headers.put("x-acs-version", VERSION);
|
||||
headers.put("x-acs-action", apiName);
|
||||
headers.put("x-acs-date", FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss'Z'", TimeZone.getTimeZone("GMT")).format(new Date()));
|
||||
headers.put("x-acs-signature-nonce", IdUtil.randomUUID());
|
||||
headers.put("x-acs-content-sha256", hashedRequestPayload);
|
||||
|
||||
// 2.2 构建签名 Header
|
||||
// 3.2 构建签名 Header
|
||||
StringBuilder canonicalHeaders = new StringBuilder(); // 构造请求头,多个规范化消息头,按照消息头名称(小写)的字符代码顺序以升序排列后拼接在一起
|
||||
StringBuilder signedHeadersBuilder = new StringBuilder(); // 已签名消息头列表,多个请求头名称(小写)按首字母升序排列并以英文分号(;)分隔
|
||||
headers.entrySet().stream().filter(entry -> entry.getKey().toLowerCase().startsWith("x-acs-")
|
||||
|| entry.getKey().equalsIgnoreCase("host")
|
||||
|| entry.getKey().equalsIgnoreCase("content-type"))
|
||||
|| "host".equalsIgnoreCase(entry.getKey())
|
||||
|| "content-type".equalsIgnoreCase(entry.getKey()))
|
||||
.sorted(Map.Entry.comparingByKey()).forEach(entry -> {
|
||||
String lowerKey = entry.getKey().toLowerCase();
|
||||
canonicalHeaders.append(lowerKey).append(":").append(String.valueOf(entry.getValue()).trim()).append("\n");
|
||||
@@ -157,13 +161,13 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
});
|
||||
String signedHeaders = signedHeadersBuilder.substring(0, signedHeadersBuilder.length() - 1);
|
||||
|
||||
// 3. 请求 Body
|
||||
String requestBody = ""; // 短信 API 为 RPC 接口,query parameters 在 uri 中拼接,因此 request body 如果没有特殊要求,设置为空。
|
||||
String hashedRequestBody = DigestUtil.sha256Hex(requestBody);
|
||||
|
||||
// 4. 构建 Authorization 签名
|
||||
String canonicalRequest = "POST" + "\n" + "/" + "\n" + queryString + "\n"
|
||||
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestBody;
|
||||
String canonicalRequest = "POST" + "\n" +
|
||||
"/" + "\n" +
|
||||
queryString + "\n" +
|
||||
canonicalHeaders + "\n" +
|
||||
signedHeaders + "\n" +
|
||||
hashedRequestPayload;
|
||||
String hashedCanonicalRequest = DigestUtil.sha256Hex(canonicalRequest);
|
||||
String stringToSign = "ACS3-HMAC-SHA256" + "\n" + hashedCanonicalRequest;
|
||||
String signature = SecureUtil.hmacSha256(properties.getApiSecret()).digestHex(stringToSign); // 计算签名
|
||||
@@ -190,4 +194,4 @@ public class AliyunSmsClient extends AbstractSmsClient {
|
||||
.replace("%7E", "~"); // 波浪号 "%7E" 被替换为 "~"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ public class TencentSmsClient extends AbstractSmsClient {
|
||||
return new SmsReceiveRespDTO()
|
||||
.setSuccess("SUCCESS".equals(statusObj.getStr("report_status"))) // 是否接收成功
|
||||
.setErrorCode(statusObj.getStr("errmsg")) // 状态报告编码
|
||||
.setErrorMsg(statusObj.getStr("description")) // 状态报告描述
|
||||
.setMobile(statusObj.getStr("mobile")) // 手机号
|
||||
.setReceiveTime(statusObj.getLocalDateTime("user_receive_time", null)) // 状态报告时间
|
||||
.setSerialNo(statusObj.getStr("sid")); // 发送序列号
|
||||
|
||||
@@ -5,6 +5,9 @@ import lombok.Data;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮箱发送消息
|
||||
*
|
||||
@@ -21,8 +24,16 @@ public class MailSendMessage {
|
||||
/**
|
||||
* 接收邮件地址
|
||||
*/
|
||||
@NotNull(message = "接收邮件地址不能为空")
|
||||
private String mail;
|
||||
@NotEmpty(message = "接收邮件地址不能为空")
|
||||
private Collection<String> toMails;
|
||||
/**
|
||||
* 抄送邮件地址
|
||||
*/
|
||||
private Collection<String> ccMails;
|
||||
/**
|
||||
* 密送邮件地址
|
||||
*/
|
||||
private Collection<String> bccMails;
|
||||
/**
|
||||
* 邮件账号编号
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,11 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
/**
|
||||
* Mail 邮件相关消息的 Producer
|
||||
*
|
||||
@@ -24,17 +29,22 @@ public class MailProducer {
|
||||
* 发送 {@link MailSendMessage} 消息
|
||||
*
|
||||
* @param sendLogId 发送日志编码
|
||||
* @param mail 接收邮件地址
|
||||
* @param toMails 接收邮件地址
|
||||
* @param ccMails 抄送邮件地址
|
||||
* @param bccMails 密送邮件地址
|
||||
* @param accountId 邮件账号编号
|
||||
* @param nickname 邮件发件人
|
||||
* @param title 邮件标题
|
||||
* @param content 邮件内容
|
||||
* @param nickname 邮件发件人
|
||||
* @param title 邮件标题
|
||||
* @param content 邮件内容
|
||||
*/
|
||||
public void sendMailSendMessage(Long sendLogId, String mail, Long accountId,
|
||||
String nickname, String title, String content) {
|
||||
public void sendMailSendMessage(Long sendLogId,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
Long accountId, String nickname, String title, String content) {
|
||||
MailSendMessage message = new MailSendMessage()
|
||||
.setLogId(sendLogId).setMail(mail).setAccountId(accountId)
|
||||
.setNickname(nickname).setTitle(title).setContent(content);
|
||||
.setLogId(sendLogId)
|
||||
.setToMails(toMails).setCcMails(ccMails).setBccMails(bccMails)
|
||||
.setAccountId(accountId).setNickname(nickname)
|
||||
.setTitle(title).setContent(content);
|
||||
applicationContext.publishEvent(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
||||
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
|
||||
@@ -97,6 +98,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataPermission(enable = false)
|
||||
public AuthLoginRespVO login(AuthLoginReqVO reqVO) {
|
||||
// 校验验证码
|
||||
validateCaptcha(reqVO);
|
||||
|
||||
@@ -36,6 +36,13 @@ public interface DeptService {
|
||||
*/
|
||||
void deleteDept(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除部门
|
||||
*
|
||||
* @param ids 部门编号数组
|
||||
*/
|
||||
void deleteDeptList(List<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得部门信息
|
||||
*
|
||||
|
||||
@@ -88,6 +88,21 @@ public class DeptServiceImpl implements DeptService {
|
||||
deptMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
|
||||
public void deleteDeptList(List<Long> ids) {
|
||||
// 校验是否有子部门
|
||||
for (Long id : ids) {
|
||||
if (deptMapper.selectCountByParentId(id) > 0) {
|
||||
throw exception(DEPT_EXITS_CHILDREN);
|
||||
}
|
||||
}
|
||||
|
||||
// 批量删除部门
|
||||
deptMapper.deleteByIds(ids);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void validateDeptExists(Long id) {
|
||||
if (id == null) {
|
||||
|
||||
@@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailLogDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -35,18 +37,21 @@ public interface MailLogService {
|
||||
/**
|
||||
* 创建邮件日志
|
||||
*
|
||||
* @param userId 用户编码
|
||||
* @param userType 用户类型
|
||||
* @param toMail 收件人邮件
|
||||
* @param account 邮件账号信息
|
||||
* @param template 模版信息
|
||||
* @param userId 用户编码
|
||||
* @param userType 用户类型
|
||||
* @param toMails 收件人邮件
|
||||
* @param ccMails 收件人邮件
|
||||
* @param bccMails 收件人邮件
|
||||
* @param account 邮件账号信息
|
||||
* @param template 模版信息
|
||||
* @param templateContent 模版内容
|
||||
* @param templateParams 模版参数
|
||||
* @param isSend 是否发送成功
|
||||
* @param templateParams 模版参数
|
||||
* @param isSend 是否发送成功
|
||||
* @return 日志编号
|
||||
*/
|
||||
Long createMailLog(Long userId, Integer userType, String toMail,
|
||||
MailAccountDO account, MailTemplateDO template ,
|
||||
Long createMailLog(Long userId, Integer userType,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
MailAccountDO account, MailTemplateDO template,
|
||||
String templateContent, Map<String, Object> templateParams, Boolean isSend);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.mail.vo.log.MailLogPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailAccountDO;
|
||||
@@ -12,8 +13,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.hutool.core.exceptions.ExceptionUtil.getRootCauseMessage;
|
||||
|
||||
@@ -41,7 +41,8 @@ public class MailLogServiceImpl implements MailLogService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long createMailLog(Long userId, Integer userType, String toMail,
|
||||
public Long createMailLog(Long userId, Integer userType,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
MailAccountDO account, MailTemplateDO template,
|
||||
String templateContent, Map<String, Object> templateParams, Boolean isSend) {
|
||||
MailLogDO.MailLogDOBuilder logDOBuilder = MailLogDO.builder();
|
||||
@@ -49,7 +50,8 @@ public class MailLogServiceImpl implements MailLogService {
|
||||
logDOBuilder.sendStatus(Objects.equals(isSend, true) ? MailSendStatusEnum.INIT.getStatus()
|
||||
: MailSendStatusEnum.IGNORE.getStatus())
|
||||
// 用户信息
|
||||
.userId(userId).userType(userType).toMail(toMail)
|
||||
.userId(userId).userType(userType)
|
||||
.toMails(ListUtil.toList(toMails)).ccMails(ListUtil.toList(ccMails)).bccMails(ListUtil.toList(bccMails))
|
||||
.accountId(account.getId()).fromMail(account.getMail())
|
||||
// 模板相关字段
|
||||
.templateId(template.getId()).templateCode(template.getCode()).templateNickname(template.getNickname())
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.module.system.mq.message.mail.MailSendMessage;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -15,38 +17,53 @@ public interface MailSendService {
|
||||
/**
|
||||
* 发送单条邮件给管理后台的用户
|
||||
*
|
||||
* @param mail 邮箱
|
||||
* @param userId 用户编码
|
||||
* @param toMails 收件邮箱
|
||||
* @param ccMails 抄送邮箱
|
||||
* @param bccMails 密送邮箱
|
||||
* @param templateCode 邮件模版编码
|
||||
* @param templateParams 邮件模版参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleMailToAdmin(String mail, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
default Long sendSingleMailToAdmin(Long userId,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.ADMIN.getValue(),
|
||||
templateCode, templateParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送单条邮件给用户 APP 的用户
|
||||
*
|
||||
* @param mail 邮箱
|
||||
* @param userId 用户编码
|
||||
* @param toMails 收件邮箱
|
||||
* @param ccMails 抄送邮箱
|
||||
* @param bccMails 密送邮箱
|
||||
* @param templateCode 邮件模版编码
|
||||
* @param templateParams 邮件模版参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleMailToMember(String mail, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
default Long sendSingleMailToMember(Long userId,
|
||||
Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
return sendSingleMail(toMails, ccMails, bccMails, userId, UserTypeEnum.MEMBER.getValue(),
|
||||
templateCode, templateParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送单条邮件给用户
|
||||
* 发送单条邮件
|
||||
*
|
||||
* @param mail 邮箱
|
||||
* @param userId 用户编码
|
||||
* @param toMails 收件邮箱
|
||||
* @param ccMails 抄送邮箱
|
||||
* @param bccMails 密送邮箱
|
||||
* @param userId 用户编号
|
||||
* @param userType 用户类型
|
||||
* @param templateCode 邮件模版编码
|
||||
* @param templateParams 邮件模版参数
|
||||
* @return 发送日志编号
|
||||
*/
|
||||
Long sendSingleMail(String mail, Long userId, Integer userType,
|
||||
Long sendSingleMail(Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams);
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package cn.iocoder.yudao.module.system.service.mail;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.mail.MailAccount;
|
||||
import cn.hutool.extra.mail.MailUtil;
|
||||
@@ -18,6 +20,8 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@@ -50,56 +54,67 @@ public class MailSendServiceImpl implements MailSendService {
|
||||
private MailProducer mailProducer;
|
||||
|
||||
@Override
|
||||
public Long sendSingleMailToAdmin(String mail, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
// 如果 mail 为空,则加载用户编号对应的邮箱
|
||||
if (StrUtil.isEmpty(mail)) {
|
||||
AdminUserDO user = adminUserService.getUser(userId);
|
||||
if (user != null) {
|
||||
mail = user.getEmail();
|
||||
}
|
||||
}
|
||||
// 执行发送
|
||||
return sendSingleMail(mail, userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long sendSingleMailToMember(String mail, Long userId,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
// 如果 mail 为空,则加载用户编号对应的邮箱
|
||||
if (StrUtil.isEmpty(mail)) {
|
||||
mail = memberService.getMemberUserEmail(userId);
|
||||
}
|
||||
// 执行发送
|
||||
return sendSingleMail(mail, userId, UserTypeEnum.MEMBER.getValue(), templateCode, templateParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long sendSingleMail(String mail, Long userId, Integer userType,
|
||||
public Long sendSingleMail(Collection<String> toMails, Collection<String> ccMails, Collection<String> bccMails,
|
||||
Long userId, Integer userType,
|
||||
String templateCode, Map<String, Object> templateParams) {
|
||||
// 校验邮箱模版是否合法
|
||||
// 1.1 校验邮箱模版是否合法
|
||||
MailTemplateDO template = validateMailTemplate(templateCode);
|
||||
// 校验邮箱账号是否合法
|
||||
// 1.2 校验邮箱账号是否合法
|
||||
MailAccountDO account = validateMailAccount(template.getAccountId());
|
||||
|
||||
// 校验邮箱是否存在
|
||||
mail = validateMail(mail);
|
||||
// 1.3 校验邮件参数是否缺失
|
||||
validateTemplateParams(template, templateParams);
|
||||
|
||||
// 2. 组装邮箱
|
||||
String userMail = getUserMail(userId, userType);
|
||||
Collection<String> toMailSet = new LinkedHashSet<>();
|
||||
Collection<String> ccMailSet = new LinkedHashSet<>();
|
||||
Collection<String> bccMailSet = new LinkedHashSet<>();
|
||||
if (Validator.isEmail(userMail)) {
|
||||
toMailSet.add(userMail);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(toMails)) {
|
||||
toMails.stream().filter(Validator::isEmail).forEach(toMailSet::add);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(ccMails)) {
|
||||
ccMails.stream().filter(Validator::isEmail).forEach(ccMailSet::add);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(bccMails)) {
|
||||
bccMails.stream().filter(Validator::isEmail).forEach(bccMailSet::add);
|
||||
}
|
||||
if (CollUtil.isEmpty(toMailSet)) {
|
||||
throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
|
||||
}
|
||||
|
||||
// 创建发送日志。如果模板被禁用,则不发送短信,只记录日志
|
||||
Boolean isSend = CommonStatusEnum.ENABLE.getStatus().equals(template.getStatus());
|
||||
String title = mailTemplateService.formatMailTemplateContent(template.getTitle(), templateParams);
|
||||
String content = mailTemplateService.formatMailTemplateContent(template.getContent(), templateParams);
|
||||
Long sendLogId = mailLogService.createMailLog(userId, userType, mail,
|
||||
Long sendLogId = mailLogService.createMailLog(userId, userType, toMailSet, ccMailSet, bccMailSet,
|
||||
account, template, content, templateParams, isSend);
|
||||
// 发送 MQ 消息,异步执行发送短信
|
||||
if (isSend) {
|
||||
mailProducer.sendMailSendMessage(sendLogId, mail, account.getId(),
|
||||
template.getNickname(), title, content);
|
||||
mailProducer.sendMailSendMessage(sendLogId, toMailSet, ccMailSet, bccMailSet,
|
||||
account.getId(), template.getNickname(), title, content);
|
||||
}
|
||||
return sendLogId;
|
||||
}
|
||||
|
||||
private String getUserMail(Long userId, Integer userType) {
|
||||
if (userId == null || userType == null) {
|
||||
return null;
|
||||
}
|
||||
if (UserTypeEnum.ADMIN.getValue().equals(userType)) {
|
||||
AdminUserDO user = adminUserService.getUser(userId);
|
||||
if (user != null) {
|
||||
return user.getEmail();
|
||||
}
|
||||
}
|
||||
if (UserTypeEnum.MEMBER.getValue().equals(userType)) {
|
||||
return memberService.getMemberUserEmail(userId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doSendMail(MailSendMessage message) {
|
||||
// 1. 创建发送账号
|
||||
@@ -107,7 +122,7 @@ public class MailSendServiceImpl implements MailSendService {
|
||||
MailAccount mailAccount = buildMailAccount(account, message.getNickname());
|
||||
// 2. 发送邮件
|
||||
try {
|
||||
String messageId = MailUtil.send(mailAccount, message.getMail(),
|
||||
String messageId = MailUtil.send(mailAccount, message.getToMails(), message.getCcMails(), message.getBccMails(),
|
||||
message.getTitle(), message.getContent(), true);
|
||||
// 3. 更新结果(成功)
|
||||
mailLogService.updateMailSendResult(message.getLogId(), messageId, null);
|
||||
@@ -147,16 +162,8 @@ public class MailSendServiceImpl implements MailSendService {
|
||||
return account;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String validateMail(String mail) {
|
||||
if (StrUtil.isEmpty(mail)) {
|
||||
throw exception(MAIL_SEND_MAIL_NOT_EXISTS);
|
||||
}
|
||||
return mail;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验邮件参数是否确实
|
||||
* 校验邮件参数是否缺失
|
||||
*
|
||||
* @param template 邮箱模板
|
||||
* @param templateParams 参数列表
|
||||
|
||||
@@ -86,8 +86,8 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService {
|
||||
|
||||
@Override
|
||||
public OAuth2AccessTokenDO grantClientCredentials(String clientId, List<String> scopes) {
|
||||
// TODO 芋艿:项目中使用 OAuth2 解决的是三方应用的授权,内部的 SSO 等问题,所以暂时不考虑 client_credentials 这个场景
|
||||
throw new UnsupportedOperationException("暂时不支持 client_credentials 授权模式");
|
||||
// 特殊:https://yuanbao.tencent.com/bot/app/share/chat/wFj642xSZHHx
|
||||
return oauth2TokenService.createAccessToken(0L, UserTypeEnum.ADMIN.getValue(), clientId, scopes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -197,6 +197,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
* @return 用户信息
|
||||
*/
|
||||
private Map<String, String> buildUserInfo(Long userId, Integer userType) {
|
||||
if (userId == null || userId <= 0) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
|
||||
AdminUserDO user = adminUserService.getUser(userId);
|
||||
return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
|
||||
@@ -205,7 +208,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
// 注意:目前 Member 暂时不读取,可以按需实现
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return null;
|
||||
throw new IllegalArgumentException("未知用户类型:" + userType);
|
||||
}
|
||||
|
||||
private static String generateAccessToken() {
|
||||
|
||||
@@ -255,9 +255,6 @@ public class MenuServiceImpl implements MenuService {
|
||||
return;
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的菜单
|
||||
if (id == null) {
|
||||
throw exception(MENU_NAME_DUPLICATE);
|
||||
}
|
||||
if (!menu.getId().equals(id)) {
|
||||
throw exception(MENU_NAME_DUPLICATE);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.Map;
|
||||
* 短信日志 Service 接口
|
||||
*
|
||||
* @author zzf
|
||||
* @date 13:48 2021/3/2
|
||||
* @since 13:48 2021/3/2
|
||||
*/
|
||||
public interface SmsLogService {
|
||||
|
||||
@@ -49,12 +49,13 @@ public interface SmsLogService {
|
||||
* 更新日志的接收结果
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @param apiSerialNo 发送编号
|
||||
* @param success 是否接收成功
|
||||
* @param receiveTime 用户接收时间
|
||||
* @param apiReceiveCode API 接收结果的编码
|
||||
* @param apiReceiveMsg API 接收结果的说明
|
||||
*/
|
||||
void updateSmsReceiveResult(Long id, Boolean success,
|
||||
void updateSmsReceiveResult(Long id, String apiSerialNo, Boolean success,
|
||||
LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg);
|
||||
|
||||
/**
|
||||
|
||||
@@ -63,10 +63,17 @@ public class SmsLogServiceImpl implements SmsLogService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSmsReceiveResult(Long id, Boolean success, LocalDateTime receiveTime,
|
||||
public void updateSmsReceiveResult(Long id, String apiSerialNo, Boolean success, LocalDateTime receiveTime,
|
||||
String apiReceiveCode, String apiReceiveMsg) {
|
||||
SmsReceiveStatusEnum receiveStatus = Objects.equals(success, true) ?
|
||||
SmsReceiveStatusEnum.SUCCESS : SmsReceiveStatusEnum.FAILURE;
|
||||
if (id == null || id == 0) {
|
||||
SmsLogDO log = smsLogMapper.selectByApiSerialNo(apiSerialNo);
|
||||
if (log == null) {
|
||||
return;
|
||||
}
|
||||
id = log.getId();
|
||||
}
|
||||
smsLogMapper.updateById(SmsLogDO.builder().id(id).receiveStatus(receiveStatus.getStatus())
|
||||
.receiveTime(receiveTime).apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build());
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ public class SmsSendServiceImpl implements SmsSendService {
|
||||
return;
|
||||
}
|
||||
// 更新短信日志的接收结果. 因为量一般不大,所以先使用 for 循环更新
|
||||
receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(result.getLogId(),
|
||||
receiveResults.forEach(result -> smsLogService.updateSmsReceiveResult(result.getLogId(), result.getSerialNo(),
|
||||
result.getSuccess(), result.getReceiveTime(), result.getErrorCode(), result.getErrorMsg()));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.service.tenant;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
@@ -102,7 +101,7 @@ public class TenantServiceImpl implements TenantService {
|
||||
// 校验租户名称是否重复
|
||||
validTenantNameDuplicate(createReqVO.getName(), null);
|
||||
// 校验租户域名是否重复
|
||||
validTenantWebsiteDuplicate(createReqVO.getWebsite(), null);
|
||||
validTenantWebsiteDuplicate(createReqVO.getWebsites(), null);
|
||||
// 校验套餐被禁用
|
||||
TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(createReqVO.getPackageId());
|
||||
|
||||
@@ -148,7 +147,7 @@ public class TenantServiceImpl implements TenantService {
|
||||
// 校验租户名称是否重复
|
||||
validTenantNameDuplicate(updateReqVO.getName(), updateReqVO.getId());
|
||||
// 校验租户域名是否重复
|
||||
validTenantWebsiteDuplicate(updateReqVO.getWebsite(), updateReqVO.getId());
|
||||
validTenantWebsiteDuplicate(updateReqVO.getWebsites(), updateReqVO.getId());
|
||||
// 校验套餐被禁用
|
||||
TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId());
|
||||
|
||||
@@ -175,21 +174,19 @@ public class TenantServiceImpl implements TenantService {
|
||||
}
|
||||
}
|
||||
|
||||
private void validTenantWebsiteDuplicate(String website, Long id) {
|
||||
if (StrUtil.isEmpty(website)) {
|
||||
private void validTenantWebsiteDuplicate(List<String> websites, Long excludeId) {
|
||||
if (CollUtil.isEmpty(websites)) {
|
||||
return;
|
||||
}
|
||||
TenantDO tenant = tenantMapper.selectByWebsite(website);
|
||||
if (tenant == null) {
|
||||
return;
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同名字的租户
|
||||
if (id == null) {
|
||||
throw exception(TENANT_WEBSITE_DUPLICATE, website);
|
||||
}
|
||||
if (!tenant.getId().equals(id)) {
|
||||
throw exception(TENANT_WEBSITE_DUPLICATE, website);
|
||||
}
|
||||
websites.forEach(website -> {
|
||||
List<TenantDO> tenants = tenantMapper.selectListByWebsite(website);
|
||||
if (excludeId != null) {
|
||||
tenants.removeIf(tenant -> tenant.getId().equals(excludeId));
|
||||
}
|
||||
if (CollUtil.isNotEmpty(tenants)) {
|
||||
throw exception(TENANT_WEBSITE_DUPLICATE, website);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,7 +260,8 @@ public class TenantServiceImpl implements TenantService {
|
||||
|
||||
@Override
|
||||
public TenantDO getTenantByWebsite(String website) {
|
||||
return tenantMapper.selectByWebsite(website);
|
||||
List<TenantDO> tenants = tenantMapper.selectListByWebsite(website);
|
||||
return CollUtil.getFirst(tenants);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
cn.iocoder.yudao.module.system.framework.captcha.core.PictureWordCaptchaServiceImpl
|
||||
Reference in New Issue
Block a user